1use super::prelude::*;
2use crate::{AngleOrNumber, NoneOr, NumberOrPercentage};
3
4#[derive(Parse, Peek, IntoCursor, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
6#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
7#[derive(csskit_derives::NodeWithMetadata)]
8pub enum ColorSpace {
9 #[atom(CssAtomSet::Srgb)]
10 Srgb(T![Ident]),
11 #[atom(CssAtomSet::SrgbLinear)]
12 SrgbLinear(T![Ident]),
13 #[atom(CssAtomSet::DisplayP3)]
14 DisplayP3(T![Ident]),
15 #[atom(CssAtomSet::A98Rgb)]
16 A98Rgb(T![Ident]),
17 #[atom(CssAtomSet::ProphotoRgb)]
18 ProphotoRgb(T![Ident]),
19 #[atom(CssAtomSet::Rec2020)]
20 Rec2020(T![Ident]),
21 #[atom(CssAtomSet::Xyz)]
22 Xyz(T![Ident]),
23 #[atom(CssAtomSet::XyzD50)]
24 XyzD50(T![Ident]),
25 #[atom(CssAtomSet::XyzD65)]
26 XyzD65(T![Ident]),
27}
28
29#[derive(IntoCursor, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
31#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
32#[derive(csskit_derives::NodeWithMetadata)]
33pub struct CommaOrSlash(Cursor);
34
35impl<'a> Peek<'a> for CommaOrSlash {
36 fn peek<I>(_: &Parser<'a, I>, c: Cursor) -> bool
37 where
38 I: Iterator<Item = Cursor> + Clone,
39 {
40 c == ',' || c == '/'
41 }
42}
43
44impl<'a> Parse<'a> for CommaOrSlash {
45 fn parse<I>(p: &mut Parser<'a, I>) -> ParserResult<Self>
46 where
47 I: Iterator<Item = Cursor> + Clone,
48 {
49 if !p.peek::<Self>() {
50 Err(Diagnostic::new(p.next(), Diagnostic::unexpected))?
51 }
52 Ok(Self(p.next()))
53 }
54}
55
56#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
58#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
59#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
60#[derive(csskit_derives::NodeWithMetadata)]
61pub enum ColorFunction {
62 Color(ColorFunctionColor),
63 Rgb(RgbFunction),
64 Rgba(RgbaFunction),
65 Hsl(HslFunction),
66 Hsla(HslaFunction),
67 Hwb(HwbFunction),
68 Lab(LabFunction),
69 Lch(LchFunction),
70 Oklab(OklabFunction),
71 Oklch(OklchFunction),
72}
73
74#[cfg(feature = "chromashift")]
75impl crate::ToChromashift for ColorFunction {
76 fn to_chromashift(&self) -> Option<chromashift::Color> {
77 match self {
78 Self::Color(c) => c.to_chromashift(),
79 Self::Rgb(c) => c.to_chromashift(),
80 Self::Rgba(c) => c.to_chromashift(),
81 Self::Hsl(c) => c.to_chromashift(),
82 Self::Hsla(c) => c.to_chromashift(),
83 Self::Hwb(c) => c.to_chromashift(),
84 Self::Lab(c) => c.to_chromashift(),
85 Self::Lch(c) => c.to_chromashift(),
86 Self::Oklab(c) => c.to_chromashift(),
87 Self::Oklch(c) => c.to_chromashift(),
88 }
89 }
90}
91
92#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
103#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
104#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
105#[derive(csskit_derives::NodeWithMetadata)]
106pub struct ColorFunctionColor {
107 #[atom(CssAtomSet::Color)]
108 pub name: T![Function],
109 pub params: ColorFunctionColorParams,
110 pub close: T![')'],
111}
112
113#[cfg(feature = "chromashift")]
114impl crate::ToChromashift for ColorFunctionColor {
115 fn to_chromashift(&self) -> Option<chromashift::Color> {
116 todo!();
117 }
118}
119
120#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
121#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
122#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
123#[derive(csskit_derives::NodeWithMetadata)]
124pub struct ColorFunctionColorParams(
125 pub ColorSpace,
126 pub NoneOr<NumberOrPercentage>,
127 pub NoneOr<NumberOrPercentage>,
128 pub NoneOr<NumberOrPercentage>,
129 pub Option<T![/]>,
130 pub Option<NoneOr<NumberOrPercentage>>,
131);
132
133#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
150#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
151#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
152#[derive(csskit_derives::NodeWithMetadata)]
153pub struct RgbFunction {
154 #[atom(CssAtomSet::Rgb)]
155 pub name: T![Function],
156 pub params: RgbFunctionParams,
157 pub close: T![')'],
158}
159
160#[cfg(feature = "chromashift")]
161impl crate::ToChromashift for RgbFunction {
162 fn to_chromashift(&self) -> Option<chromashift::Color> {
163 self.params.to_chromashift()
164 }
165}
166
167#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
168#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
169#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
170#[derive(csskit_derives::NodeWithMetadata)]
171pub struct RgbaFunction {
172 #[atom(CssAtomSet::Rgba)]
173 pub name: T![Function],
174 pub params: RgbFunctionParams,
175 pub close: T![')'],
176}
177
178#[cfg(feature = "chromashift")]
179impl crate::ToChromashift for RgbaFunction {
180 fn to_chromashift(&self) -> Option<chromashift::Color> {
181 self.params.to_chromashift()
182 }
183}
184
185#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
186#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
187#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
188#[derive(csskit_derives::NodeWithMetadata)]
189pub struct RgbFunctionParams(
190 pub NoneOr<NumberOrPercentage>,
191 pub Option<T![,]>,
192 pub NoneOr<NumberOrPercentage>,
193 pub Option<T![,]>,
194 pub NoneOr<NumberOrPercentage>,
195 pub Option<CommaOrSlash>,
196 pub Option<NoneOr<NumberOrPercentage>>,
197);
198
199#[cfg(feature = "chromashift")]
200impl crate::ToChromashift for RgbFunctionParams {
201 fn to_chromashift(&self) -> Option<chromashift::Color> {
202 use chromashift::Srgb;
203 let Self(red, _, green, _, blue, _, alpha) = &self;
204 let alpha = match alpha {
205 Some(NoneOr::None(_)) => 0.0,
206 Some(NoneOr::Some(NumberOrPercentage::Number(t))) => t.value() * 100.0,
207 Some(NoneOr::Some(NumberOrPercentage::Percentage(t))) => t.value(),
208 None => 100.0,
209 };
210 let red = match red {
211 NoneOr::None(_) => {
212 return None;
213 }
214 NoneOr::Some(NumberOrPercentage::Number(red)) => red.value(),
215 NoneOr::Some(NumberOrPercentage::Percentage(red)) => red.value() / 100.0 * 255.0,
216 } as u8;
217 let green = match green {
218 NoneOr::None(_) => {
219 return None;
220 }
221 NoneOr::Some(NumberOrPercentage::Number(green)) => green.value(),
222 NoneOr::Some(NumberOrPercentage::Percentage(green)) => green.value() / 100.0 * 255.0,
223 } as u8;
224 let blue = match blue {
225 NoneOr::None(_) => {
226 return None;
227 }
228 NoneOr::Some(NumberOrPercentage::Number(blue)) => blue.value(),
229 NoneOr::Some(NumberOrPercentage::Percentage(blue)) => blue.value() / 100.0 * 255.0,
230 } as u8;
231 Some(chromashift::Color::Srgb(Srgb::new(red, green, blue, alpha)))
232 }
233}
234
235#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
254#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
255#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
256#[derive(csskit_derives::NodeWithMetadata)]
257pub struct HslFunction {
258 #[atom(CssAtomSet::Hsl)]
259 pub name: T![Function],
260 pub params: HslFunctionParams,
261 pub close: T![')'],
262}
263
264#[cfg(feature = "chromashift")]
265impl crate::ToChromashift for HslFunction {
266 fn to_chromashift(&self) -> Option<chromashift::Color> {
267 self.params.to_chromashift()
268 }
269}
270
271#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
272#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
273#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
274#[derive(csskit_derives::NodeWithMetadata)]
275pub struct HslaFunction {
276 #[atom(CssAtomSet::Hsla)]
277 pub name: T![Function],
278 pub params: HslFunctionParams,
279 pub close: T![')'],
280}
281
282#[cfg(feature = "chromashift")]
283impl crate::ToChromashift for HslaFunction {
284 fn to_chromashift(&self) -> Option<chromashift::Color> {
285 self.params.to_chromashift()
286 }
287}
288
289#[derive(Parse, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
290#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
291#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
292#[derive(csskit_derives::NodeWithMetadata)]
293pub struct HslFunctionParams(
294 pub NoneOr<AngleOrNumber>,
295 pub Option<T![,]>,
296 pub NoneOr<NumberOrPercentage>,
297 pub Option<T![,]>,
298 pub NoneOr<NumberOrPercentage>,
299 pub Option<CommaOrSlash>,
300 pub Option<NoneOr<NumberOrPercentage>>,
301);
302
303#[cfg(feature = "chromashift")]
304impl crate::ToChromashift for HslFunctionParams {
305 fn to_chromashift(&self) -> Option<chromashift::Color> {
306 use chromashift::Hsl;
307 let Self(hue, _, saturation, _, lightness, _, alpha) = &self;
308 let hue = match hue {
309 NoneOr::None(_) => {
310 return None;
311 }
312 NoneOr::Some(AngleOrNumber::Number(hue)) => hue.value(),
313 NoneOr::Some(AngleOrNumber::Angle(d)) => d.as_degrees(),
314 };
315 let saturation = match saturation {
316 NoneOr::None(_) => {
317 return None;
318 }
319 NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
320 NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value(),
321 };
322 let lightness = match lightness {
323 NoneOr::None(_) => {
324 return None;
325 }
326 NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
327 NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value(),
328 };
329 let alpha = match alpha {
330 Some(NoneOr::None(_)) => 0.0,
331 Some(NoneOr::Some(NumberOrPercentage::Number(t))) => t.value() * 100.0,
332 Some(NoneOr::Some(NumberOrPercentage::Percentage(t))) => t.value(),
333 None => 100.0,
334 };
335 Some(chromashift::Color::Hsl(Hsl::new(hue, saturation, lightness, alpha)))
336 }
337}
338
339#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
346#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
347#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
348#[derive(csskit_derives::NodeWithMetadata)]
349pub struct HwbFunction {
350 #[atom(CssAtomSet::Hwb)]
351 pub name: T![Function],
352 pub params: HwbFunctionParams,
353 pub close: T![')'],
354}
355
356#[cfg(feature = "chromashift")]
357impl crate::ToChromashift for HwbFunction {
358 fn to_chromashift(&self) -> Option<chromashift::Color> {
359 use chromashift::Hwb;
360 let HwbFunctionParams(hue, whiteness, blackness, _, alpha) = &self.params;
361 let hue = match hue {
362 NoneOr::None(_) => {
363 return None;
364 }
365 NoneOr::Some(AngleOrNumber::Number(hue)) => hue.value(),
366 NoneOr::Some(AngleOrNumber::Angle(d)) => d.as_degrees(),
367 };
368 let whiteness = match whiteness {
369 NoneOr::None(_) => {
370 return None;
371 }
372 NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
373 NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value(),
374 };
375 let blackness = match blackness {
376 NoneOr::None(_) => {
377 return None;
378 }
379 NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
380 NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value(),
381 };
382 let alpha = match alpha {
383 Some(NoneOr::None(_)) => 0.0,
384 Some(NoneOr::Some(NumberOrPercentage::Number(t))) => t.value() * 100.0,
385 Some(NoneOr::Some(NumberOrPercentage::Percentage(t))) => t.value(),
386 None => 100.0,
387 };
388 Some(chromashift::Color::Hwb(Hwb::new(hue, whiteness, blackness, alpha)))
389 }
390}
391
392#[derive(Parse, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
393#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
394#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
395#[derive(csskit_derives::NodeWithMetadata)]
396pub struct HwbFunctionParams(
397 pub NoneOr<AngleOrNumber>,
398 pub NoneOr<NumberOrPercentage>,
399 pub NoneOr<NumberOrPercentage>,
400 pub Option<T![/]>,
401 pub Option<NoneOr<NumberOrPercentage>>,
402);
403
404#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
413#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
414#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
415#[derive(csskit_derives::NodeWithMetadata)]
416pub struct LabFunction {
417 #[atom(CssAtomSet::Lab)]
418 pub name: T![Function],
419 pub params: LabFunctionParams,
420 pub close: T![')'],
421}
422
423#[cfg(feature = "chromashift")]
424impl crate::ToChromashift for LabFunction {
425 fn to_chromashift(&self) -> Option<chromashift::Color> {
426 use chromashift::Lab;
427 let LabFunctionParams(l, a, b, _, alpha) = &self.params;
428 let l = match l {
429 NoneOr::None(_) => {
430 return None;
431 }
432 NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
433 NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value(),
434 } as f64;
435 let a = match a {
436 NoneOr::None(_) => {
437 return None;
438 }
439 NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
440 NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value() / 100.0 * 125.0,
441 } as f64;
442 let b = match b {
443 NoneOr::None(_) => {
444 return None;
445 }
446 NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
447 NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value() / 100.0 * 125.0,
448 } as f64;
449 let alpha = match alpha {
450 Some(NoneOr::None(_)) => 0.0,
451 Some(NoneOr::Some(NumberOrPercentage::Number(t))) => t.value() * 100.0,
452 Some(NoneOr::Some(NumberOrPercentage::Percentage(t))) => t.value(),
453 None => 100.0,
454 };
455 Some(chromashift::Color::Lab(Lab::new(l, a, b, alpha)))
456 }
457}
458
459#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
460#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
461#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
462#[derive(csskit_derives::NodeWithMetadata)]
463pub struct LabFunctionParams(
464 pub NoneOr<NumberOrPercentage>,
465 pub NoneOr<NumberOrPercentage>,
466 pub NoneOr<NumberOrPercentage>,
467 pub Option<T![/]>,
468 pub Option<NoneOr<NumberOrPercentage>>,
469);
470
471#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
480#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
481#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
482#[derive(csskit_derives::NodeWithMetadata)]
483pub struct LchFunction {
484 #[atom(CssAtomSet::Lch)]
485 pub name: T![Function],
486 pub params: LchFunctionParams,
487 pub close: T![')'],
488}
489
490#[cfg(feature = "chromashift")]
491impl crate::ToChromashift for LchFunction {
492 fn to_chromashift(&self) -> Option<chromashift::Color> {
493 use chromashift::Lch;
494 let LchFunctionParams(lightness, chroma, hue, _, alpha) = &self.params;
495 let lightness = match lightness {
496 NoneOr::None(_) => {
497 return None;
498 }
499 NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
500 NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value(),
501 } as f64;
502 let chroma = match chroma {
503 NoneOr::None(_) => {
504 return None;
505 }
506 NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
507 NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value() / 100.0 * 150.0,
508 } as f64;
509 let hue = match hue {
510 NoneOr::None(_) => {
511 return None;
512 }
513 NoneOr::Some(AngleOrNumber::Number(hue)) => hue.value(),
514 NoneOr::Some(AngleOrNumber::Angle(d)) => d.as_degrees(),
515 } as f64;
516 let alpha = match alpha {
517 Some(NoneOr::None(_)) => 0.0,
518 Some(NoneOr::Some(NumberOrPercentage::Number(t))) => t.value() * 100.0,
519 Some(NoneOr::Some(NumberOrPercentage::Percentage(t))) => t.value(),
520 None => 100.0,
521 };
522 Some(chromashift::Color::Lch(Lch::new(lightness, chroma, hue, alpha)))
523 }
524}
525
526#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
527#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
528#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
529#[derive(csskit_derives::NodeWithMetadata)]
530pub struct LchFunctionParams(
531 pub NoneOr<NumberOrPercentage>,
532 pub NoneOr<NumberOrPercentage>,
533 pub NoneOr<AngleOrNumber>,
534 pub Option<T![/]>,
535 pub Option<NoneOr<NumberOrPercentage>>,
536);
537
538#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
547#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
548#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
549#[derive(csskit_derives::NodeWithMetadata)]
550pub struct OklabFunction {
551 #[atom(CssAtomSet::Oklab)]
552 pub name: T![Function],
553 pub params: LabFunctionParams,
554 pub close: T![')'],
555}
556
557#[cfg(feature = "chromashift")]
558impl crate::ToChromashift for OklabFunction {
559 fn to_chromashift(&self) -> Option<chromashift::Color> {
560 use chromashift::Oklab;
561 let LabFunctionParams(l, a, b, _, alpha) = &self.params;
562 let alpha = match alpha {
563 Some(NoneOr::None(_)) => 0.0,
564 Some(NoneOr::Some(NumberOrPercentage::Number(t))) => t.value() * 100.0,
565 Some(NoneOr::Some(NumberOrPercentage::Percentage(t))) => t.value(),
566 None => 100.0,
567 };
568 let l = match l {
569 NoneOr::None(_) => {
570 return None;
571 }
572 NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
573 NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value() / 100.0,
574 } as f64;
575 let a = match a {
576 NoneOr::None(_) => {
577 return None;
578 }
579 NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
580 NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value() / 100.0 * 0.4,
581 } as f64;
582 let b = match b {
583 NoneOr::None(_) => {
584 return None;
585 }
586 NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
587 NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value() / 100.0 * 0.4,
588 } as f64;
589 Some(chromashift::Color::Oklab(Oklab::new(l, a, b, alpha)))
590 }
591}
592
593#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
602#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
603#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
604#[derive(csskit_derives::NodeWithMetadata)]
605pub struct OklchFunction {
606 #[atom(CssAtomSet::Oklch)]
607 pub name: T![Function],
608 pub params: LchFunctionParams,
609 pub close: T![')'],
610}
611
612#[cfg(feature = "chromashift")]
613impl crate::ToChromashift for OklchFunction {
614 fn to_chromashift(&self) -> Option<chromashift::Color> {
615 use chromashift::Oklch;
616 let LchFunctionParams(lightness, chroma, hue, _, alpha) = &self.params;
617 let lightness = match lightness {
618 NoneOr::None(_) => {
619 return None;
620 }
621 NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
622 NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value(),
623 } as f64;
624 let chroma = match chroma {
625 NoneOr::None(_) => {
626 return None;
627 }
628 NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
629 NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value() / 100.0 * 150.0,
630 } as f64;
631 let hue = match hue {
632 NoneOr::None(_) => {
633 return None;
634 }
635 NoneOr::Some(AngleOrNumber::Number(hue)) => hue.value(),
636 NoneOr::Some(AngleOrNumber::Angle(d)) => d.as_degrees(),
637 } as f64;
638 let alpha = match alpha {
639 Some(NoneOr::None(_)) => 0.0,
640 Some(NoneOr::Some(NumberOrPercentage::Number(t))) => t.value() * 100.0,
641 Some(NoneOr::Some(NumberOrPercentage::Percentage(t))) => t.value(),
642 None => 100.0,
643 };
644 Some(chromashift::Color::Oklch(Oklch::new(lightness, chroma, hue, alpha)))
645 }
646}
647
648#[cfg(test)]
649mod tests {
650 use super::*;
651
652 #[test]
653 fn size_test() {
654 assert_eq!(std::mem::size_of::<ColorFunction>(), 140);
655 assert_eq!(std::mem::size_of::<ColorFunctionColor>(), 120);
656 assert_eq!(std::mem::size_of::<RgbFunction>(), 136);
657 assert_eq!(std::mem::size_of::<RgbaFunction>(), 136);
658 assert_eq!(std::mem::size_of::<HslFunction>(), 136);
659 assert_eq!(std::mem::size_of::<HslaFunction>(), 136);
660 assert_eq!(std::mem::size_of::<HwbFunction>(), 104);
661 assert_eq!(std::mem::size_of::<LabFunction>(), 104);
662 assert_eq!(std::mem::size_of::<LchFunction>(), 104);
663 assert_eq!(std::mem::size_of::<OklabFunction>(), 104);
664 assert_eq!(std::mem::size_of::<OklchFunction>(), 104);
665 }
666}