Skip to main content

material_colors/scheme/
mod.rs

1#![allow(clippy::too_many_arguments)]
2use crate::{color::Argb, dynamic_color::DynamicScheme, palette::CorePalette, Map};
3#[cfg(not(feature = "std"))]
4use alloc::string::String;
5use core::{array::IntoIter, fmt};
6#[cfg(feature = "serde")]
7use serde::Serialize;
8#[cfg(feature = "std")]
9use std::string::String;
10
11pub mod variant;
12
13#[derive(Debug, PartialEq, Eq)]
14#[cfg_attr(feature = "serde", derive(Serialize))]
15pub struct Scheme {
16    pub primary: Argb,
17    pub on_primary: Argb,
18    pub primary_container: Argb,
19    pub on_primary_container: Argb,
20    pub inverse_primary: Argb,
21    pub primary_fixed: Argb,
22    pub primary_fixed_dim: Argb,
23    pub on_primary_fixed: Argb,
24    pub on_primary_fixed_variant: Argb,
25    pub secondary: Argb,
26    pub on_secondary: Argb,
27    pub secondary_container: Argb,
28    pub on_secondary_container: Argb,
29    pub secondary_fixed: Argb,
30    pub secondary_fixed_dim: Argb,
31    pub on_secondary_fixed: Argb,
32    pub on_secondary_fixed_variant: Argb,
33    pub tertiary: Argb,
34    pub on_tertiary: Argb,
35    pub tertiary_container: Argb,
36    pub on_tertiary_container: Argb,
37    pub tertiary_fixed: Argb,
38    pub tertiary_fixed_dim: Argb,
39    pub on_tertiary_fixed: Argb,
40    pub on_tertiary_fixed_variant: Argb,
41    pub error: Argb,
42    pub on_error: Argb,
43    pub error_container: Argb,
44    pub on_error_container: Argb,
45    pub surface_dim: Argb,
46    pub surface: Argb,
47    pub surface_tint: Argb,
48    pub surface_bright: Argb,
49    pub surface_container_lowest: Argb,
50    pub surface_container_low: Argb,
51    pub surface_container: Argb,
52    pub surface_container_high: Argb,
53    pub surface_container_highest: Argb,
54    pub on_surface: Argb,
55    pub on_surface_variant: Argb,
56    pub outline: Argb,
57    pub outline_variant: Argb,
58    pub inverse_surface: Argb,
59    pub inverse_on_surface: Argb,
60    pub surface_variant: Argb,
61    pub background: Argb,
62    pub on_background: Argb,
63    pub shadow: Argb,
64    pub scrim: Argb,
65}
66
67impl fmt::Display for Scheme {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        f.debug_struct("Scheme")
70            .field("primary", &self.primary)
71            .field("on_primary", &self.on_primary)
72            .field("primary_container", &self.primary_container)
73            .field("on_primary_container", &self.on_primary_container)
74            .field("inverse_primary", &self.inverse_primary)
75            .field("primary_fixed", &self.primary_fixed)
76            .field("primary_fixed_dim", &self.primary_fixed_dim)
77            .field("on_primary_fixed", &self.on_primary_fixed)
78            .field("on_primary_fixed_variant", &self.on_primary_fixed_variant)
79            .field("secondary", &self.secondary)
80            .field("on_secondary", &self.on_secondary)
81            .field("secondary_container", &self.secondary_container)
82            .field("on_secondary_container", &self.on_secondary_container)
83            .field("secondary_fixed", &self.secondary_fixed)
84            .field("secondary_fixed_dim", &self.secondary_fixed_dim)
85            .field("on_secondary_fixed", &self.on_secondary_fixed)
86            .field(
87                "on_secondary_fixed_variant",
88                &self.on_secondary_fixed_variant,
89            )
90            .field("tertiary", &self.tertiary)
91            .field("on_tertiary", &self.on_tertiary)
92            .field("tertiary_container", &self.tertiary_container)
93            .field("on_tertiary_container", &self.on_tertiary_container)
94            .field("tertiary_fixed", &self.tertiary_fixed)
95            .field("tertiary_fixed_dim", &self.tertiary_fixed_dim)
96            .field("on_tertiary_fixed", &self.on_tertiary_fixed)
97            .field("on_tertiary_fixed_variant", &self.on_tertiary_fixed_variant)
98            .field("error", &self.error)
99            .field("on_error", &self.on_error)
100            .field("error_container", &self.error_container)
101            .field("on_error_container", &self.on_error_container)
102            .field("surface_dim", &self.surface_dim)
103            .field("surface", &self.surface)
104            .field("surface_tint", &self.surface_tint)
105            .field("surface_bright", &self.surface_bright)
106            .field("surface_container_lowest", &self.surface_container_lowest)
107            .field("surface_container_low", &self.surface_container_low)
108            .field("surface_container", &self.surface_container)
109            .field("surface_container_high", &self.surface_container_high)
110            .field("surface_container_highest", &self.surface_container_highest)
111            .field("on_surface", &self.on_surface)
112            .field("on_surface_variant", &self.on_surface_variant)
113            .field("outline", &self.outline)
114            .field("outline_variant", &self.outline_variant)
115            .field("inverse_surface", &self.inverse_surface)
116            .field("inverse_on_surface", &self.inverse_on_surface)
117            .field("surface_variant", &self.surface_variant)
118            .field("background", &self.background)
119            .field("on_background", &self.on_background)
120            .field("shadow", &self.shadow)
121            .field("scrim", &self.scrim)
122            .finish()
123    }
124}
125
126impl Scheme {
127    pub const fn new(
128        primary: Argb,
129        on_primary: Argb,
130        primary_container: Argb,
131        on_primary_container: Argb,
132        inverse_primary: Argb,
133        primary_fixed: Argb,
134        primary_fixed_dim: Argb,
135        on_primary_fixed: Argb,
136        on_primary_fixed_variant: Argb,
137        secondary: Argb,
138        on_secondary: Argb,
139        secondary_container: Argb,
140        on_secondary_container: Argb,
141        secondary_fixed: Argb,
142        secondary_fixed_dim: Argb,
143        on_secondary_fixed: Argb,
144        on_secondary_fixed_variant: Argb,
145        tertiary: Argb,
146        on_tertiary: Argb,
147        tertiary_container: Argb,
148        on_tertiary_container: Argb,
149        tertiary_fixed: Argb,
150        tertiary_fixed_dim: Argb,
151        on_tertiary_fixed: Argb,
152        on_tertiary_fixed_variant: Argb,
153        error: Argb,
154        on_error: Argb,
155        error_container: Argb,
156        on_error_container: Argb,
157        surface_dim: Argb,
158        surface: Argb,
159        surface_tint: Argb,
160        surface_bright: Argb,
161        surface_container_lowest: Argb,
162        surface_container_low: Argb,
163        surface_container: Argb,
164        surface_container_high: Argb,
165        surface_container_highest: Argb,
166        on_surface: Argb,
167        on_surface_variant: Argb,
168        outline: Argb,
169        outline_variant: Argb,
170        inverse_surface: Argb,
171        inverse_on_surface: Argb,
172        surface_variant: Argb,
173        background: Argb,
174        on_background: Argb,
175        shadow: Argb,
176        scrim: Argb,
177    ) -> Self {
178        Self {
179            primary,
180            on_primary,
181            primary_container,
182            on_primary_container,
183            inverse_primary,
184            primary_fixed,
185            primary_fixed_dim,
186            on_primary_fixed,
187            on_primary_fixed_variant,
188            secondary,
189            on_secondary,
190            secondary_container,
191            on_secondary_container,
192            secondary_fixed,
193            secondary_fixed_dim,
194            on_secondary_fixed,
195            on_secondary_fixed_variant,
196            tertiary,
197            on_tertiary,
198            tertiary_container,
199            on_tertiary_container,
200            tertiary_fixed,
201            tertiary_fixed_dim,
202            on_tertiary_fixed,
203            on_tertiary_fixed_variant,
204            error,
205            on_error,
206            error_container,
207            on_error_container,
208            surface_dim,
209            surface,
210            surface_tint,
211            surface_bright,
212            surface_container_lowest,
213            surface_container_low,
214            surface_container,
215            surface_container_high,
216            surface_container_highest,
217            on_surface,
218            on_surface_variant,
219            outline,
220            outline_variant,
221            inverse_surface,
222            inverse_on_surface,
223            surface_variant,
224            background,
225            on_background,
226            shadow,
227            scrim,
228        }
229    }
230}
231
232impl From<DynamicScheme> for Scheme {
233    fn from(scheme: DynamicScheme) -> Self {
234        Self::new(
235            scheme.primary(),
236            scheme.on_primary(),
237            scheme.primary_container(),
238            scheme.on_primary_container(),
239            scheme.inverse_primary(),
240            scheme.primary_fixed(),
241            scheme.primary_fixed_dim(),
242            scheme.on_primary_fixed(),
243            scheme.on_primary_fixed_variant(),
244            scheme.secondary(),
245            scheme.on_secondary(),
246            scheme.secondary_container(),
247            scheme.on_secondary_container(),
248            scheme.secondary_fixed(),
249            scheme.secondary_fixed_dim(),
250            scheme.on_secondary_fixed(),
251            scheme.on_secondary_fixed_variant(),
252            scheme.tertiary(),
253            scheme.on_tertiary(),
254            scheme.tertiary_container(),
255            scheme.on_tertiary_container(),
256            scheme.tertiary_fixed(),
257            scheme.tertiary_fixed_dim(),
258            scheme.on_tertiary_fixed(),
259            scheme.on_tertiary_fixed_variant(),
260            scheme.error(),
261            scheme.on_error(),
262            scheme.error_container(),
263            scheme.on_error_container(),
264            scheme.surface_dim(),
265            scheme.surface(),
266            scheme.surface_tint(),
267            scheme.surface_bright(),
268            scheme.surface_container_lowest(),
269            scheme.surface_container_low(),
270            scheme.surface_container(),
271            scheme.surface_container_high(),
272            scheme.surface_container_highest(),
273            scheme.on_surface(),
274            scheme.on_surface_variant(),
275            scheme.outline(),
276            scheme.outline_variant(),
277            scheme.inverse_surface(),
278            scheme.inverse_on_surface(),
279            scheme.surface_variant(),
280            scheme.background(),
281            scheme.on_background(),
282            scheme.shadow(),
283            scheme.scrim(),
284        )
285    }
286}
287
288impl IntoIterator for Scheme {
289    type Item = (String, Argb);
290
291    type IntoIter = IntoIter<(String, Argb), 49>;
292
293    fn into_iter(self) -> Self::IntoIter {
294        [
295            ("primary".into(), self.primary),
296            ("on_primary".into(), self.on_primary),
297            ("primary_container".into(), self.primary_container),
298            ("on_primary_container".into(), self.on_primary_container),
299            ("inverse_primary".into(), self.inverse_primary),
300            ("primary_fixed".into(), self.primary_fixed),
301            ("primary_fixed_dim".into(), self.primary_fixed_dim),
302            ("on_primary_fixed".into(), self.on_primary_fixed),
303            (
304                "on_primary_fixed_variant".into(),
305                self.on_primary_fixed_variant,
306            ),
307            ("secondary".into(), self.secondary),
308            ("on_secondary".into(), self.on_secondary),
309            ("secondary_container".into(), self.secondary_container),
310            ("on_secondary_container".into(), self.on_secondary_container),
311            ("secondary_fixed".into(), self.secondary_fixed),
312            ("secondary_fixed_dim".into(), self.secondary_fixed_dim),
313            ("on_secondary_fixed".into(), self.on_secondary_fixed),
314            (
315                "on_secondary_fixed_variant".into(),
316                self.on_secondary_fixed_variant,
317            ),
318            ("tertiary".into(), self.tertiary),
319            ("on_tertiary".into(), self.on_tertiary),
320            ("tertiary_container".into(), self.tertiary_container),
321            ("on_tertiary_container".into(), self.on_tertiary_container),
322            ("tertiary_fixed".into(), self.tertiary_fixed),
323            ("tertiary_fixed_dim".into(), self.tertiary_fixed_dim),
324            ("on_tertiary_fixed".into(), self.on_tertiary_fixed),
325            (
326                "on_tertiary_fixed_variant".into(),
327                self.on_tertiary_fixed_variant,
328            ),
329            ("error".into(), self.error),
330            ("on_error".into(), self.on_error),
331            ("error_container".into(), self.error_container),
332            ("on_error_container".into(), self.on_error_container),
333            ("surface_dim".into(), self.surface_dim),
334            ("surface".into(), self.surface),
335            ("surface_tint".into(), self.surface_tint),
336            ("surface_bright".into(), self.surface_bright),
337            (
338                "surface_container_lowest".into(),
339                self.surface_container_lowest,
340            ),
341            ("surface_container_low".into(), self.surface_container_low),
342            ("surface_container".into(), self.surface_container),
343            ("surface_container_high".into(), self.surface_container_high),
344            (
345                "surface_container_highest".into(),
346                self.surface_container_highest,
347            ),
348            ("on_surface".into(), self.on_surface),
349            ("on_surface_variant".into(), self.on_surface_variant),
350            ("outline".into(), self.outline),
351            ("outline_variant".into(), self.outline_variant),
352            ("inverse_surface".into(), self.inverse_surface),
353            ("inverse_on_surface".into(), self.inverse_on_surface),
354            ("surface_variant".into(), self.surface_variant),
355            ("background".into(), self.background),
356            ("on_background".into(), self.on_background),
357            ("shadow".into(), self.shadow),
358            ("scrim".into(), self.scrim),
359        ]
360        .into_iter()
361    }
362}
363
364impl From<Scheme> for Map<String, String> {
365    fn from(value: Scheme) -> Self {
366        let map: Map<String, Argb> = Map::from_iter(value);
367
368        map.into_iter()
369            .map(|(key, value)| (key, value.to_hex_with_pound()))
370            .collect()
371    }
372}
373
374/// This is similar to `MaterialLightColorSchemeFromPalette` and `MaterialDarkColorSchemeFromPalette` in the C++ implementation of Material Color Utilities.
375///
376/// We use this to test scheme generation from a core palette.
377#[derive(PartialEq, Eq, Debug)]
378pub struct SchemeFromPalette {
379    pub primary: Argb,
380    pub on_primary: Argb,
381    pub primary_container: Argb,
382    pub on_primary_container: Argb,
383    pub secondary: Argb,
384    pub on_secondary: Argb,
385    pub secondary_container: Argb,
386    pub on_secondary_container: Argb,
387    pub tertiary: Argb,
388    pub on_tertiary: Argb,
389    pub tertiary_container: Argb,
390    pub on_tertiary_container: Argb,
391    pub error: Argb,
392    pub on_error: Argb,
393    pub error_container: Argb,
394    pub on_error_container: Argb,
395    pub surface: Argb,
396    pub on_surface: Argb,
397    pub surface_variant: Argb,
398    pub on_surface_variant: Argb,
399    pub outline: Argb,
400    pub outline_variant: Argb,
401    pub background: Argb,
402    pub on_background: Argb,
403    pub shadow: Argb,
404    pub scrim: Argb,
405    pub inverse_surface: Argb,
406    pub inverse_on_surface: Argb,
407    pub inverse_primary: Argb,
408}
409
410impl SchemeFromPalette {
411    /// Generates a light color scheme from a core palette.
412    /// This has less fields than [`Scheme`]
413    pub fn light_from_palette(palette: &CorePalette) -> Self {
414        Self {
415            primary: palette.primary.tone(40),
416            on_primary: palette.primary.tone(100),
417            primary_container: palette.primary.tone(90),
418            on_primary_container: palette.primary.tone(10),
419            secondary: palette.secondary.tone(40),
420            on_secondary: palette.secondary.tone(100),
421            secondary_container: palette.secondary.tone(90),
422            on_secondary_container: palette.secondary.tone(10),
423            tertiary: palette.tertiary.tone(40),
424            on_tertiary: palette.tertiary.tone(100),
425            tertiary_container: palette.tertiary.tone(90),
426            on_tertiary_container: palette.tertiary.tone(10),
427            error: palette.error.tone(40),
428            on_error: palette.error.tone(100),
429            error_container: palette.error.tone(90),
430            on_error_container: palette.error.tone(10),
431            background: palette.neutral.tone(99),
432            on_background: palette.neutral.tone(10),
433            surface: palette.neutral.tone(99),
434            on_surface: palette.neutral.tone(10),
435            surface_variant: palette.neutral_variant.tone(90),
436            on_surface_variant: palette.neutral_variant.tone(30),
437            outline: palette.neutral_variant.tone(50),
438            outline_variant: palette.neutral_variant.tone(80),
439            shadow: palette.neutral.tone(0),
440            scrim: palette.neutral.tone(0),
441            inverse_surface: palette.neutral.tone(20),
442            inverse_on_surface: palette.neutral.tone(95),
443            inverse_primary: palette.primary.tone(80),
444        }
445    }
446
447    /// Generates a dark color scheme from a core palette.
448    /// This has less fields than [`Scheme`]
449    pub fn dark_from_palette(palette: &CorePalette) -> Self {
450        Self {
451            primary: palette.primary.tone(80),
452            on_primary: palette.primary.tone(20),
453            primary_container: palette.primary.tone(30),
454            on_primary_container: palette.primary.tone(90),
455            secondary: palette.secondary.tone(80),
456            on_secondary: palette.secondary.tone(20),
457            secondary_container: palette.secondary.tone(30),
458            on_secondary_container: palette.secondary.tone(90),
459            tertiary: palette.tertiary.tone(80),
460            on_tertiary: palette.tertiary.tone(20),
461            tertiary_container: palette.tertiary.tone(30),
462            on_tertiary_container: palette.tertiary.tone(90),
463            error: palette.error.tone(80),
464            on_error: palette.error.tone(20),
465            error_container: palette.error.tone(30),
466            on_error_container: palette.error.tone(80),
467            background: palette.neutral.tone(10),
468            on_background: palette.neutral.tone(90),
469            surface: palette.neutral.tone(10),
470            on_surface: palette.neutral.tone(90),
471            surface_variant: palette.neutral_variant.tone(30),
472            on_surface_variant: palette.neutral_variant.tone(80),
473            outline: palette.neutral_variant.tone(60),
474            outline_variant: palette.neutral_variant.tone(30),
475            shadow: palette.neutral.tone(0),
476            scrim: palette.neutral.tone(0),
477            inverse_surface: palette.neutral.tone(90),
478            inverse_on_surface: palette.neutral.tone(20),
479            inverse_primary: palette.primary.tone(40),
480        }
481    }
482
483    pub fn light(argb: Argb) -> Self {
484        Self::light_from_palette(&CorePalette::of(argb))
485    }
486
487    pub fn light_content(argb: Argb) -> Self {
488        Self::light_from_palette(&CorePalette::content_of(argb))
489    }
490
491    pub fn dark(argb: Argb) -> Self {
492        Self::dark_from_palette(&CorePalette::of(argb))
493    }
494
495    pub fn dark_content(argb: Argb) -> Self {
496        Self::dark_from_palette(&CorePalette::content_of(argb))
497    }
498}
499
500impl PartialEq<Scheme> for SchemeFromPalette {
501    fn eq(&self, other: &Scheme) -> bool {
502        self.primary == other.primary
503            && self.on_primary == other.on_primary
504            && self.primary_container == other.primary_container
505            && self.on_primary_container == other.on_primary_container
506            && self.secondary == other.secondary
507            && self.on_secondary == other.on_secondary
508            && self.secondary_container == other.secondary_container
509            && self.on_secondary_container == other.on_secondary_container
510            && self.tertiary == other.tertiary
511            && self.on_tertiary == other.on_tertiary
512            && self.tertiary_container == other.tertiary_container
513            && self.on_tertiary_container == other.on_tertiary_container
514            && self.error == other.error
515            && self.on_error == other.on_error
516            && self.error_container == other.error_container
517            && self.on_error_container == other.on_error_container
518            && self.surface == other.surface
519            && self.on_surface == other.on_surface
520            && self.surface_variant == other.surface_variant
521            && self.on_surface_variant == other.on_surface_variant
522            && self.outline == other.outline
523            && self.outline_variant == other.outline_variant
524            && self.background == other.background
525            && self.on_background == other.on_background
526            && self.shadow == other.shadow
527            && self.scrim == other.scrim
528            && self.inverse_surface == other.inverse_surface
529            && self.inverse_on_surface == other.inverse_on_surface
530            && self.inverse_primary == other.inverse_primary
531    }
532}
533
534#[cfg(test)]
535mod tests {
536    use crate::color::Argb;
537    use crate::scheme::SchemeFromPalette;
538    use float_cmp::assert_approx_eq;
539
540    #[test]
541    fn test_surface_tones() {
542        let c = Argb::from_u32(0xffff0000);
543
544        let light = SchemeFromPalette::light(c);
545        let dark = SchemeFromPalette::dark(c);
546
547        assert_approx_eq!(f64, light.surface.as_lstar(), 99.0, epsilon = 0.1); // 99.015;
548        assert_approx_eq!(f64, dark.surface.as_lstar(), 10.0, epsilon = 0.1); // 9.923
549    }
550
551    #[test]
552    fn test_blue_scheme() {
553        let c = Argb::from_u32(0xff0000ff);
554
555        let light = SchemeFromPalette::light(c);
556        let dark = SchemeFromPalette::dark(c);
557
558        assert_eq!(light.primary.to_hex(), "343dff");
559        assert_eq!(dark.primary.to_hex(), "bec2ff");
560    }
561
562    #[test]
563    fn test_light_scheme_from_high_chroma_color() {
564        let c = Argb::from_u32(0xfffa2bec);
565
566        let scheme = SchemeFromPalette::light(c);
567
568        let expected = SchemeFromPalette {
569            primary: Argb::from_u32(0xffab00a2),
570            on_primary: Argb::from_u32(0xffffffff),
571            primary_container: Argb::from_u32(0xffffd7f3),
572            on_primary_container: Argb::from_u32(0xff390035),
573            secondary: Argb::from_u32(0xff6e5868),
574            on_secondary: Argb::from_u32(0xffffffff),
575            secondary_container: Argb::from_u32(0xfff8daee),
576            on_secondary_container: Argb::from_u32(0xff271624),
577            tertiary: Argb::from_u32(0xff815343),
578            on_tertiary: Argb::from_u32(0xffffffff),
579            tertiary_container: Argb::from_u32(0xffffdbd0),
580            on_tertiary_container: Argb::from_u32(0xff321207),
581            error: Argb::from_u32(0xffba1a1a),
582            on_error: Argb::from_u32(0xffffffff),
583            error_container: Argb::from_u32(0xffffdad6),
584            on_error_container: Argb::from_u32(0xff410002),
585            background: Argb::from_u32(0xfffffbff),
586            on_background: Argb::from_u32(0xff1f1a1d),
587            surface: Argb::from_u32(0xfffffbff),
588            on_surface: Argb::from_u32(0xff1f1a1d),
589            surface_variant: Argb::from_u32(0xffeedee7),
590            on_surface_variant: Argb::from_u32(0xff4e444b),
591            outline: Argb::from_u32(0xff80747b),
592            outline_variant: Argb::from_u32(0xffd2c2cb),
593            shadow: Argb::from_u32(0xff000000),
594            scrim: Argb::from_u32(0xff000000),
595            inverse_surface: Argb::from_u32(0xff342f32),
596            inverse_on_surface: Argb::from_u32(0xfff8eef2),
597            inverse_primary: Argb::from_u32(0xffffabee),
598        };
599
600        assert_eq!(scheme, expected);
601    }
602
603    #[test]
604    fn test_dark_scheme_from_high_chroma_color() {
605        let c = Argb::from_u32(0xfffa2bec);
606
607        let scheme = SchemeFromPalette::dark(c);
608
609        let expected = SchemeFromPalette {
610            primary: Argb::from_u32(0xffffabee),
611            on_primary: Argb::from_u32(0xff5c0057),
612            primary_container: Argb::from_u32(0xff83007b),
613            on_primary_container: Argb::from_u32(0xffffd7f3),
614            secondary: Argb::from_u32(0xffdbbed1),
615            on_secondary: Argb::from_u32(0xff3e2a39),
616            secondary_container: Argb::from_u32(0xff554050),
617            on_secondary_container: Argb::from_u32(0xfff8daee),
618            tertiary: Argb::from_u32(0xfff5b9a5),
619            on_tertiary: Argb::from_u32(0xff4c2619),
620            tertiary_container: Argb::from_u32(0xff663c2d),
621            on_tertiary_container: Argb::from_u32(0xffffdbd0),
622            error: Argb::from_u32(0xffffb4ab),
623            on_error: Argb::from_u32(0xff690005),
624            error_container: Argb::from_u32(0xff93000a),
625            on_error_container: Argb::from_u32(0xffffb4ab),
626            background: Argb::from_u32(0xff1f1a1d),
627            on_background: Argb::from_u32(0xffeae0e4),
628            surface: Argb::from_u32(0xff1f1a1d),
629            on_surface: Argb::from_u32(0xffeae0e4),
630            surface_variant: Argb::from_u32(0xff4e444b),
631            on_surface_variant: Argb::from_u32(0xffd2c2cb),
632            outline: Argb::from_u32(0xff9a8d95),
633            outline_variant: Argb::from_u32(0xff4e444b),
634            shadow: Argb::from_u32(0xff000000),
635            scrim: Argb::from_u32(0xff000000),
636            inverse_surface: Argb::from_u32(0xffeae0e4),
637            inverse_on_surface: Argb::from_u32(0xff342f32),
638            inverse_primary: Argb::from_u32(0xffab00a2),
639        };
640
641        assert_eq!(scheme, expected);
642    }
643
644    #[test]
645    fn test_light_content_scheme_from_high_chroma_color() {
646        let c = Argb::from_u32(0xfffa2bec);
647
648        let scheme = SchemeFromPalette::light_content(c);
649
650        let expected = SchemeFromPalette {
651            primary: Argb::from_u32(0xffab00a2),
652            on_primary: Argb::from_u32(0xffffffff),
653            primary_container: Argb::from_u32(0xffffd7f3),
654            on_primary_container: Argb::from_u32(0xff390035),
655            secondary: Argb::from_u32(0xff7f4e75),
656            on_secondary: Argb::from_u32(0xffffffff),
657            secondary_container: Argb::from_u32(0xffffd7f3),
658            on_secondary_container: Argb::from_u32(0xff330b2f),
659            tertiary: Argb::from_u32(0xff9c4323),
660            on_tertiary: Argb::from_u32(0xffffffff),
661            tertiary_container: Argb::from_u32(0xffffdbd0),
662            on_tertiary_container: Argb::from_u32(0xff390c00),
663            error: Argb::from_u32(0xffba1a1a),
664            on_error: Argb::from_u32(0xffffffff),
665            error_container: Argb::from_u32(0xffffdad6),
666            on_error_container: Argb::from_u32(0xff410002),
667            background: Argb::from_u32(0xfffffbff),
668            on_background: Argb::from_u32(0xff1f1a1d),
669            surface: Argb::from_u32(0xfffffbff),
670            on_surface: Argb::from_u32(0xff1f1a1d),
671            surface_variant: Argb::from_u32(0xffeedee7),
672            on_surface_variant: Argb::from_u32(0xff4e444b),
673            outline: Argb::from_u32(0xff80747b),
674            outline_variant: Argb::from_u32(0xffd2c2cb),
675            shadow: Argb::from_u32(0xff000000),
676            scrim: Argb::from_u32(0xff000000),
677            inverse_surface: Argb::from_u32(0xff342f32),
678            inverse_on_surface: Argb::from_u32(0xfff8eef2),
679            inverse_primary: Argb::from_u32(0xffffabee),
680        };
681
682        assert_eq!(scheme, expected);
683    }
684
685    #[test]
686    fn test_dark_content_scheme_from_high_chroma_color() {
687        let c = Argb::from_u32(0xfffa2bec);
688
689        let scheme = SchemeFromPalette::dark_content(c);
690
691        let expected = SchemeFromPalette {
692            primary: Argb::from_u32(0xffffabee),
693            on_primary: Argb::from_u32(0xff5c0057),
694            primary_container: Argb::from_u32(0xff83007b),
695            on_primary_container: Argb::from_u32(0xffffd7f3),
696            secondary: Argb::from_u32(0xfff0b4e1),
697            on_secondary: Argb::from_u32(0xff4b2145),
698            secondary_container: Argb::from_u32(0xff64375c),
699            on_secondary_container: Argb::from_u32(0xffffd7f3),
700            tertiary: Argb::from_u32(0xffffb59c),
701            on_tertiary: Argb::from_u32(0xff5c1900),
702            tertiary_container: Argb::from_u32(0xff7d2c0d),
703            on_tertiary_container: Argb::from_u32(0xffffdbd0),
704            error: Argb::from_u32(0xffffb4ab),
705            on_error: Argb::from_u32(0xff690005),
706            error_container: Argb::from_u32(0xff93000a),
707            on_error_container: Argb::from_u32(0xffffb4ab),
708            background: Argb::from_u32(0xff1f1a1d),
709            on_background: Argb::from_u32(0xffeae0e4),
710            surface: Argb::from_u32(0xff1f1a1d),
711            on_surface: Argb::from_u32(0xffeae0e4),
712            surface_variant: Argb::from_u32(0xff4e444b),
713            on_surface_variant: Argb::from_u32(0xffd2c2cb),
714            outline: Argb::from_u32(0xff9a8d95),
715            outline_variant: Argb::from_u32(0xff4e444b),
716            shadow: Argb::from_u32(0xff000000),
717            scrim: Argb::from_u32(0xff000000),
718            inverse_surface: Argb::from_u32(0xffeae0e4),
719            inverse_on_surface: Argb::from_u32(0xff342f32),
720            inverse_primary: Argb::from_u32(0xffab00a2),
721        };
722
723        assert_eq!(scheme, expected);
724    }
725}