use super::prelude::*;
use crate::functions::color_mix_function::ColorMixFunction;
use crate::functions::light_dark_function::LightDarkFunction;
use crate::functions::relative_color::RelativeColorFunction;
use crate::{AngleOrNumber, NoneOr, NumberOrPercentage};
use css_parse::BumpBox;
#[derive(
Parse, Peek, IntoCursor, ToSpan, SemanticEq, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash,
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum ColorSpace {
#[atom(CssAtomSet::Srgb)]
Srgb(T![Ident]),
#[atom(CssAtomSet::SrgbLinear)]
SrgbLinear(T![Ident]),
#[atom(CssAtomSet::DisplayP3)]
DisplayP3(T![Ident]),
#[atom(CssAtomSet::A98Rgb)]
A98Rgb(T![Ident]),
#[atom(CssAtomSet::ProphotoRgb)]
ProphotoRgb(T![Ident]),
#[atom(CssAtomSet::Rec2020)]
Rec2020(T![Ident]),
#[atom(CssAtomSet::Xyz)]
Xyz(T![Ident]),
#[atom(CssAtomSet::XyzD50)]
XyzD50(T![Ident]),
#[atom(CssAtomSet::XyzD65)]
XyzD65(T![Ident]),
}
#[derive(IntoCursor, ToSpan, SemanticEq, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub struct CommaOrSlash(Cursor);
impl<'a> Peek<'a> for CommaOrSlash {
const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::Delim]);
#[inline(always)]
fn peek<I>(_: &Parser<'a, I>, c: Cursor) -> bool
where
I: Iterator<Item = Cursor> + Clone,
{
c == ',' || c == '/'
}
}
impl<'a> Parse<'a> for CommaOrSlash {
fn parse<I>(p: &mut Parser<'a, I>) -> ParserResult<Self>
where
I: Iterator<Item = Cursor> + Clone,
{
if !p.peek::<Self>() {
Err(Diagnostic::new(p.next(), Diagnostic::unexpected))?
}
Ok(Self(p.next()))
}
}
#[derive(Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(all))]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum ColorFunction<'a> {
Relative(BumpBox<'a, RelativeColorFunction<'a>>),
Color(BumpBox<'a, ColorFunctionColor>),
ColorMix(BumpBox<'a, ColorMixFunction<'a>>),
LightDark(BumpBox<'a, LightDarkFunction<'a>>),
Rgb(RgbFunction),
Rgba(RgbaFunction),
Hsl(HslFunction),
Hsla(HslaFunction),
Hwb(HwbFunction),
Lab(LabFunction),
Lch(LchFunction),
Oklab(OklabFunction),
Oklch(OklchFunction),
}
impl<'a> Parse<'a> for ColorFunction<'a> {
fn parse<I>(p: &mut Parser<'a, I>) -> ParserResult<Self>
where
I: Iterator<Item = Cursor> + Clone,
{
if p.peek::<BumpBox<RelativeColorFunction>>() {
return Ok(Self::Relative(p.parse()?));
}
if p.peek::<BumpBox<ColorFunctionColor>>() {
return Ok(Self::Color(p.parse()?));
}
if p.peek::<BumpBox<ColorMixFunction>>() {
return Ok(Self::ColorMix(p.parse()?));
}
if p.peek::<BumpBox<LightDarkFunction>>() {
return Ok(Self::LightDark(p.parse()?));
}
if p.peek::<RgbFunction>() {
return Ok(Self::Rgb(p.parse()?));
}
if p.peek::<RgbaFunction>() {
return Ok(Self::Rgba(p.parse()?));
}
if p.peek::<HslFunction>() {
return Ok(Self::Hsl(p.parse()?));
}
if p.peek::<HslaFunction>() {
return Ok(Self::Hsla(p.parse()?));
}
if p.peek::<HwbFunction>() {
return Ok(Self::Hwb(p.parse()?));
}
if p.peek::<LabFunction>() {
return Ok(Self::Lab(p.parse()?));
}
if p.peek::<LchFunction>() {
return Ok(Self::Lch(p.parse()?));
}
if p.peek::<OklabFunction>() {
return Ok(Self::Oklab(p.parse()?));
}
Ok(Self::Oklch(p.parse()?))
}
}
#[cfg(feature = "chromashift")]
impl crate::ToChromashift for ColorFunction<'_> {
fn to_chromashift(&self) -> Option<chromashift::Color> {
match self {
Self::Relative(r) => r.to_chromashift(),
Self::Color(c) => c.to_chromashift(),
Self::ColorMix(c) => c.to_chromashift(),
Self::LightDark(_c) => None,
Self::Rgb(c) => c.to_chromashift(),
Self::Rgba(c) => c.to_chromashift(),
Self::Hsl(c) => c.to_chromashift(),
Self::Hsla(c) => c.to_chromashift(),
Self::Hwb(c) => c.to_chromashift(),
Self::Lab(c) => c.to_chromashift(),
Self::Lch(c) => c.to_chromashift(),
Self::Oklab(c) => c.to_chromashift(),
Self::Oklch(c) => c.to_chromashift(),
}
}
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub struct ColorFunctionColor {
#[atom(CssAtomSet::Color)]
pub name: T![Function],
pub params: ColorFunctionColorParams,
pub close: T![')'],
}
#[cfg(feature = "chromashift")]
impl crate::ToChromashift for ColorFunctionColor {
fn to_chromashift(&self) -> Option<chromashift::Color> {
use chromashift::{A98Rgb, DisplayP3, LinearRgb, ProphotoRgb, Rec2020, Srgb, XyzD50, XyzD65};
let ColorFunctionColorParams(space, c1, c2, c3, _, alpha) = &self.params;
let alpha = match alpha {
Some(NoneOr::None(_)) => 0.0,
Some(NoneOr::Some(NumberOrPercentage::Number(t))) => t.value() * 100.0,
Some(NoneOr::Some(NumberOrPercentage::Percentage(t))) => t.value(),
None => 100.0,
};
let channel_unit = |c: &NoneOr<NumberOrPercentage>| -> f64 {
match c {
NoneOr::None(_) => 0.0,
NoneOr::Some(NumberOrPercentage::Number(n)) => n.value() as f64,
NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value() as f64 / 100.0,
}
};
match space {
ColorSpace::Srgb(_) => {
let r = (channel_unit(c1) * 255.0).round() as u8;
let g = (channel_unit(c2) * 255.0).round() as u8;
let b = (channel_unit(c3) * 255.0).round() as u8;
Some(chromashift::Color::Srgb(Srgb::new(r, g, b, alpha)))
}
ColorSpace::SrgbLinear(_) => {
let r = channel_unit(c1);
let g = channel_unit(c2);
let b = channel_unit(c3);
Some(chromashift::Color::LinearRgb(LinearRgb::new(r, g, b, alpha)))
}
ColorSpace::DisplayP3(_) => {
let r = channel_unit(c1);
let g = channel_unit(c2);
let b = channel_unit(c3);
Some(chromashift::Color::DisplayP3(DisplayP3::new(r, g, b, alpha)))
}
ColorSpace::A98Rgb(_) => {
let r = channel_unit(c1);
let g = channel_unit(c2);
let b = channel_unit(c3);
Some(chromashift::Color::A98Rgb(A98Rgb::new(r, g, b, alpha)))
}
ColorSpace::ProphotoRgb(_) => {
let r = channel_unit(c1);
let g = channel_unit(c2);
let b = channel_unit(c3);
Some(chromashift::Color::ProphotoRgb(ProphotoRgb::new(r, g, b, alpha)))
}
ColorSpace::Rec2020(_) => {
let r = channel_unit(c1);
let g = channel_unit(c2);
let b = channel_unit(c3);
Some(chromashift::Color::Rec2020(Rec2020::new(r, g, b, alpha)))
}
ColorSpace::Xyz(_) | ColorSpace::XyzD65(_) => {
let x = channel_unit(c1) * 100.0;
let y = channel_unit(c2) * 100.0;
let z = channel_unit(c3) * 100.0;
Some(chromashift::Color::XyzD65(XyzD65::new(x, y, z, alpha)))
}
ColorSpace::XyzD50(_) => {
let x = channel_unit(c1) * 100.0;
let y = channel_unit(c2) * 100.0;
let z = channel_unit(c3) * 100.0;
Some(chromashift::Color::XyzD50(XyzD50::new(x, y, z, alpha)))
}
}
}
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub struct ColorFunctionColorParams(
pub ColorSpace,
pub NoneOr<NumberOrPercentage>,
pub NoneOr<NumberOrPercentage>,
pub NoneOr<NumberOrPercentage>,
pub Option<T![/]>,
pub Option<NoneOr<NumberOrPercentage>>,
);
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub struct RgbFunction {
#[atom(CssAtomSet::Rgb)]
pub name: T![Function],
pub params: RgbFunctionParams,
pub close: T![')'],
}
#[cfg(feature = "chromashift")]
impl crate::ToChromashift for RgbFunction {
fn to_chromashift(&self) -> Option<chromashift::Color> {
self.params.to_chromashift()
}
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub struct RgbaFunction {
#[atom(CssAtomSet::Rgba)]
pub name: T![Function],
pub params: RgbFunctionParams,
pub close: T![')'],
}
#[cfg(feature = "chromashift")]
impl crate::ToChromashift for RgbaFunction {
fn to_chromashift(&self) -> Option<chromashift::Color> {
self.params.to_chromashift()
}
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub struct RgbFunctionParams(
pub NoneOr<NumberOrPercentage>,
pub Option<T![,]>,
pub NoneOr<NumberOrPercentage>,
pub Option<T![,]>,
pub NoneOr<NumberOrPercentage>,
pub Option<CommaOrSlash>,
pub Option<NoneOr<NumberOrPercentage>>,
);
#[cfg(feature = "chromashift")]
impl crate::ToChromashift for RgbFunctionParams {
fn to_chromashift(&self) -> Option<chromashift::Color> {
use chromashift::Srgb;
let Self(red, _, green, _, blue, _, alpha) = &self;
let alpha = match alpha {
Some(NoneOr::None(_)) => 0.0,
Some(NoneOr::Some(NumberOrPercentage::Number(t))) => t.value() * 100.0,
Some(NoneOr::Some(NumberOrPercentage::Percentage(t))) => t.value(),
None => 100.0,
};
let red = (match red {
NoneOr::None(_) => 0.0,
NoneOr::Some(NumberOrPercentage::Number(red)) => red.value(),
NoneOr::Some(NumberOrPercentage::Percentage(red)) => red.value() / 100.0 * 255.0,
})
.round() as u8;
let green = (match green {
NoneOr::None(_) => 0.0,
NoneOr::Some(NumberOrPercentage::Number(green)) => green.value(),
NoneOr::Some(NumberOrPercentage::Percentage(green)) => green.value() / 100.0 * 255.0,
})
.round() as u8;
let blue = (match blue {
NoneOr::None(_) => 0.0,
NoneOr::Some(NumberOrPercentage::Number(blue)) => blue.value(),
NoneOr::Some(NumberOrPercentage::Percentage(blue)) => blue.value() / 100.0 * 255.0,
})
.round() as u8;
Some(chromashift::Color::Srgb(Srgb::new(red, green, blue, alpha)))
}
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub struct HslFunction {
#[atom(CssAtomSet::Hsl)]
pub name: T![Function],
pub params: HslFunctionParams,
pub close: T![')'],
}
#[cfg(feature = "chromashift")]
impl crate::ToChromashift for HslFunction {
fn to_chromashift(&self) -> Option<chromashift::Color> {
self.params.to_chromashift()
}
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub struct HslaFunction {
#[atom(CssAtomSet::Hsla)]
pub name: T![Function],
pub params: HslFunctionParams,
pub close: T![')'],
}
#[cfg(feature = "chromashift")]
impl crate::ToChromashift for HslaFunction {
fn to_chromashift(&self) -> Option<chromashift::Color> {
self.params.to_chromashift()
}
}
#[derive(Parse, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub struct HslFunctionParams(
pub NoneOr<AngleOrNumber>,
pub Option<T![,]>,
pub NoneOr<NumberOrPercentage>,
pub Option<T![,]>,
pub NoneOr<NumberOrPercentage>,
pub Option<CommaOrSlash>,
pub Option<NoneOr<NumberOrPercentage>>,
);
#[cfg(feature = "chromashift")]
impl crate::ToChromashift for HslFunctionParams {
fn to_chromashift(&self) -> Option<chromashift::Color> {
use chromashift::Hsl;
let Self(hue, _, saturation, _, lightness, _, alpha) = &self;
let hue = match hue {
NoneOr::None(_) => 0.0,
NoneOr::Some(AngleOrNumber::Number(hue)) => hue.value(),
NoneOr::Some(AngleOrNumber::Angle(d)) => d.as_degrees(),
};
let saturation = match saturation {
NoneOr::None(_) => 0.0,
NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value(),
};
let lightness = match lightness {
NoneOr::None(_) => 0.0,
NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value(),
};
let alpha = match alpha {
Some(NoneOr::None(_)) => 0.0,
Some(NoneOr::Some(NumberOrPercentage::Number(t))) => t.value() * 100.0,
Some(NoneOr::Some(NumberOrPercentage::Percentage(t))) => t.value(),
None => 100.0,
};
Some(chromashift::Color::Hsl(Hsl::new(hue, saturation, lightness, alpha)))
}
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub struct HwbFunction {
#[atom(CssAtomSet::Hwb)]
pub name: T![Function],
pub params: HwbFunctionParams,
pub close: T![')'],
}
#[cfg(feature = "chromashift")]
impl crate::ToChromashift for HwbFunction {
fn to_chromashift(&self) -> Option<chromashift::Color> {
use chromashift::Hwb;
let HwbFunctionParams(hue, whiteness, blackness, _, alpha) = &self.params;
let hue = match hue {
NoneOr::None(_) => 0.0,
NoneOr::Some(AngleOrNumber::Number(hue)) => hue.value(),
NoneOr::Some(AngleOrNumber::Angle(d)) => d.as_degrees(),
};
let whiteness = match whiteness {
NoneOr::None(_) => 0.0,
NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value(),
};
let blackness = match blackness {
NoneOr::None(_) => 0.0,
NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value(),
};
let alpha = match alpha {
Some(NoneOr::None(_)) => 0.0,
Some(NoneOr::Some(NumberOrPercentage::Number(t))) => t.value() * 100.0,
Some(NoneOr::Some(NumberOrPercentage::Percentage(t))) => t.value(),
None => 100.0,
};
Some(chromashift::Color::Hwb(Hwb::new(hue, whiteness, blackness, alpha)))
}
}
#[derive(Parse, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub struct HwbFunctionParams(
pub NoneOr<AngleOrNumber>,
pub NoneOr<NumberOrPercentage>,
pub NoneOr<NumberOrPercentage>,
pub Option<T![/]>,
pub Option<NoneOr<NumberOrPercentage>>,
);
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub struct LabFunction {
#[atom(CssAtomSet::Lab)]
pub name: T![Function],
pub params: LabFunctionParams,
pub close: T![')'],
}
#[cfg(feature = "chromashift")]
impl crate::ToChromashift for LabFunction {
fn to_chromashift(&self) -> Option<chromashift::Color> {
use chromashift::Lab;
let LabFunctionParams(l, a, b, _, alpha) = &self.params;
let l = match l {
NoneOr::None(_) => 0.0,
NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value(),
} as f64;
let a = match a {
NoneOr::None(_) => 0.0,
NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value() / 100.0 * 125.0,
} as f64;
let b = match b {
NoneOr::None(_) => 0.0,
NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value() / 100.0 * 125.0,
} as f64;
let alpha = match alpha {
Some(NoneOr::None(_)) => 0.0,
Some(NoneOr::Some(NumberOrPercentage::Number(t))) => t.value() * 100.0,
Some(NoneOr::Some(NumberOrPercentage::Percentage(t))) => t.value(),
None => 100.0,
};
Some(chromashift::Color::Lab(Lab::new(l, a, b, alpha)))
}
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub struct LabFunctionParams(
pub NoneOr<NumberOrPercentage>,
pub NoneOr<NumberOrPercentage>,
pub NoneOr<NumberOrPercentage>,
pub Option<T![/]>,
pub Option<NoneOr<NumberOrPercentage>>,
);
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub struct LchFunction {
#[atom(CssAtomSet::Lch)]
pub name: T![Function],
pub params: LchFunctionParams,
pub close: T![')'],
}
#[cfg(feature = "chromashift")]
impl crate::ToChromashift for LchFunction {
fn to_chromashift(&self) -> Option<chromashift::Color> {
use chromashift::Lch;
let LchFunctionParams(lightness, chroma, hue, _, alpha) = &self.params;
let lightness = match lightness {
NoneOr::None(_) => 0.0,
NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value(),
} as f64;
let chroma = match chroma {
NoneOr::None(_) => 0.0,
NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value() / 100.0 * 150.0,
} as f64;
let hue = match hue {
NoneOr::None(_) => 0.0,
NoneOr::Some(AngleOrNumber::Number(hue)) => hue.value(),
NoneOr::Some(AngleOrNumber::Angle(d)) => d.as_degrees(),
} as f64;
let alpha = match alpha {
Some(NoneOr::None(_)) => 0.0,
Some(NoneOr::Some(NumberOrPercentage::Number(t))) => t.value() * 100.0,
Some(NoneOr::Some(NumberOrPercentage::Percentage(t))) => t.value(),
None => 100.0,
};
Some(chromashift::Color::Lch(Lch::new(lightness, chroma, hue, alpha)))
}
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub struct LchFunctionParams(
pub NoneOr<NumberOrPercentage>,
pub NoneOr<NumberOrPercentage>,
pub NoneOr<AngleOrNumber>,
pub Option<T![/]>,
pub Option<NoneOr<NumberOrPercentage>>,
);
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub struct OklabFunction {
#[atom(CssAtomSet::Oklab)]
pub name: T![Function],
pub params: LabFunctionParams,
pub close: T![')'],
}
#[cfg(feature = "chromashift")]
impl crate::ToChromashift for OklabFunction {
fn to_chromashift(&self) -> Option<chromashift::Color> {
use chromashift::Oklab;
let LabFunctionParams(l, a, b, _, alpha) = &self.params;
let alpha = match alpha {
Some(NoneOr::None(_)) => 0.0,
Some(NoneOr::Some(NumberOrPercentage::Number(t))) => t.value() * 100.0,
Some(NoneOr::Some(NumberOrPercentage::Percentage(t))) => t.value(),
None => 100.0,
};
let l = match l {
NoneOr::None(_) => 0.0,
NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value() / 100.0,
} as f64;
let a = match a {
NoneOr::None(_) => 0.0,
NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value() / 100.0 * 0.4,
} as f64;
let b = match b {
NoneOr::None(_) => 0.0,
NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value() / 100.0 * 0.4,
} as f64;
Some(chromashift::Color::Oklab(Oklab::new(l, a, b, alpha)))
}
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
#[derive(csskit_derives::NodeWithMetadata)]
pub struct OklchFunction {
#[atom(CssAtomSet::Oklch)]
pub name: T![Function],
pub params: LchFunctionParams,
pub close: T![')'],
}
#[cfg(feature = "chromashift")]
impl crate::ToChromashift for OklchFunction {
fn to_chromashift(&self) -> Option<chromashift::Color> {
use chromashift::Oklch;
let LchFunctionParams(lightness, chroma, hue, _, alpha) = &self.params;
let lightness = match lightness {
NoneOr::None(_) => 0.0,
NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value(),
} as f64;
let chroma = match chroma {
NoneOr::None(_) => 0.0,
NoneOr::Some(NumberOrPercentage::Number(n)) => n.value(),
NoneOr::Some(NumberOrPercentage::Percentage(p)) => p.value() / 100.0 * 150.0,
} as f64;
let hue = match hue {
NoneOr::None(_) => 0.0,
NoneOr::Some(AngleOrNumber::Number(hue)) => hue.value(),
NoneOr::Some(AngleOrNumber::Angle(d)) => d.as_degrees(),
} as f64;
let alpha = match alpha {
Some(NoneOr::None(_)) => 0.0,
Some(NoneOr::Some(NumberOrPercentage::Number(t))) => t.value() * 100.0,
Some(NoneOr::Some(NumberOrPercentage::Percentage(t))) => t.value(),
None => 100.0,
};
Some(chromashift::Color::Oklch(Oklch::new(lightness, chroma, hue, alpha)))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn size_test() {
assert_eq!(std::mem::size_of::<ColorFunction<'_>>(), 144);
assert_eq!(std::mem::size_of::<ColorFunctionColor>(), 120);
assert_eq!(std::mem::size_of::<RgbFunction>(), 136);
assert_eq!(std::mem::size_of::<RgbaFunction>(), 136);
assert_eq!(std::mem::size_of::<HslFunction>(), 136);
assert_eq!(std::mem::size_of::<HslaFunction>(), 136);
assert_eq!(std::mem::size_of::<HwbFunction>(), 104);
assert_eq!(std::mem::size_of::<LabFunction>(), 104);
assert_eq!(std::mem::size_of::<LchFunction>(), 104);
assert_eq!(std::mem::size_of::<OklabFunction>(), 104);
assert_eq!(std::mem::size_of::<OklchFunction>(), 104);
}
}