use css_parse::BumpBox;
use super::prelude::*;
use crate::{Length, LengthPercentage};
#[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)]
#[derive(csskit_derives::NodeWithMetadata)]
pub enum Gradient<'a> {
#[atom(CssAtomSet::LinearGradient)]
LinearGradientFunction(BumpBox<'a, LinearGradientFunction<'a>>),
#[atom(CssAtomSet::RepeatingLinearGradient)]
RepeatingLinearGradientFunction(BumpBox<'a, RepeatingLinearGradientFunction<'a>>),
#[atom(CssAtomSet::RadialGradient)]
RadialGradientFunction(BumpBox<'a, RadialGradientFunction<'a>>),
#[atom(CssAtomSet::RepeatingRadialGradient)]
RepeatingRadialGradientFunction(BumpBox<'a, RepeatingRadialGradientFunction<'a>>),
}
#[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 LinearGradientFunction<'a> {
#[atom(CssAtomSet::LinearGradient)]
pub name: T![Function],
pub params: LinearGradientFunctionParams<'a>,
pub close: T![')'],
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub struct LinearGradientFunctionParams<'a>(
Option<LinearDirection>,
Option<T![,]>,
CommaSeparated<'a, ColorStopOrHint<'a>>,
);
#[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 RepeatingLinearGradientFunction<'a> {
#[atom(CssAtomSet::RepeatingLinearGradient)]
pub name: T![Function],
pub params: RepeatingLinearGradientFunctionParams<'a>,
pub close: T![')'],
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub struct RepeatingLinearGradientFunctionParams<'a>(
Option<LinearDirection>,
Option<T![,]>,
CommaSeparated<'a, ColorStopOrHint<'a>>,
);
#[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 RadialGradientFunction<'a> {
#[atom(CssAtomSet::RadialGradient)]
pub name: T![Function],
pub params: RadialGradientFunctionParams<'a>,
pub close: T![')'],
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub struct RadialGradientFunctionParams<'a>(
Option<RadialSize>,
Option<RadialShape>,
Option<T![Ident]>,
Option<Position>,
Option<T![,]>,
CommaSeparated<'a, ColorStopOrHint<'a>>,
);
#[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 RepeatingRadialGradientFunction<'a> {
#[atom(CssAtomSet::RepeatingRadialGradient)]
pub name: T![Function],
pub params: RepeatingRadialGradientFunctionParams<'a>,
pub close: T![')'],
}
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub struct RepeatingRadialGradientFunctionParams<'a>(
Option<RadialSize>,
Option<RadialShape>,
Option<T![Ident]>,
Option<Position>,
Option<T![,]>,
CommaSeparated<'a, ColorStopOrHint<'a>>,
);
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable))]
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", visit(skip))]
pub enum NamedDirection {
#[atom(CssAtomSet::Bottom)]
Bottom(T![Ident]),
#[atom(CssAtomSet::Top)]
Top(T![Ident]),
#[atom(CssAtomSet::Left)]
Left(T![Ident]),
#[atom(CssAtomSet::Right)]
Right(T![Ident]),
}
#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub enum LinearDirection {
Angle(Angle),
Named(#[atom(CssAtomSet::To)] T![Ident], NamedDirection, Option<NamedDirection>),
}
#[derive(Peek, ToSpan, ToCursors, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub enum RadialSize {
Extent(RadialExtent),
Circular(Length),
Elliptical(LengthPercentage, LengthPercentage),
}
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable))]
#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
#[cfg_attr(feature = "visitable", visit(skip))]
pub enum RadialExtent {
#[atom(CssAtomSet::ClosestCorner)]
ClosestCorner(T![Ident]),
#[atom(CssAtomSet::ClosestSide)]
ClosestSide(T![Ident]),
#[atom(CssAtomSet::FarthestCorner)]
FarthestCorner(T![Ident]),
#[atom(CssAtomSet::FarthestSide)]
FarthestSide(T![Ident]),
}
impl<'a> Parse<'a> for RadialSize {
fn parse<I>(p: &mut Parser<'a, I>) -> ParserResult<Self>
where
I: Iterator<Item = Cursor> + Clone,
{
if let Some(extent) = p.parse_if_peek::<RadialExtent>()? {
return Ok(RadialSize::Extent(extent));
}
if p.peek::<Length>() {
let first_len = p.parse::<LengthPercentage>()?;
if !p.peek::<Length>()
&& let LengthPercentage::Length(len) = first_len
{
return Ok(Self::Circular(len));
}
let second_len = p.parse::<LengthPercentage>()?;
return Ok(Self::Elliptical(first_len, second_len));
}
let first = p.parse::<LengthPercentage>()?;
let second = p.parse::<LengthPercentage>()?;
Ok(Self::Elliptical(first, second))
}
}
#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable))]
#[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", visit(skip))]
pub enum RadialShape {
#[atom(CssAtomSet::Circle)]
Circle(T![Ident]),
#[atom(CssAtomSet::Ellipse)]
Ellipse(T![Ident]),
}
#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub enum ColorStopOrHint<'a> {
Hint(LengthPercentage),
Stop(Color<'a>, Option<LengthPercentage>),
}
#[cfg(test)]
mod tests {
use super::*;
use crate::CssAtomSet;
use css_parse::assert_parse;
#[test]
fn size_test() {
assert_eq!(std::mem::size_of::<Gradient>(), 24);
assert_eq!(std::mem::size_of::<LinearDirection>(), 44);
assert_eq!(std::mem::size_of::<RadialSize>(), 32);
assert_eq!(std::mem::size_of::<ColorStopOrHint<'_>>(), 40);
}
#[test]
fn test_writes() {
assert_parse!(CssAtomSet::ATOMS, Gradient, "linear-gradient(to bottom,yellow,blue)");
assert_parse!(CssAtomSet::ATOMS, Gradient, "linear-gradient(yellow,blue)");
assert_parse!(CssAtomSet::ATOMS, Gradient, "linear-gradient(to bottom,#fff,#fff 85%,#e6e6e6)");
assert_parse!(CssAtomSet::ATOMS, Gradient, "linear-gradient(45deg,#808080 25%,transparent 25%)");
assert_parse!(CssAtomSet::ATOMS, Gradient, "linear-gradient(to right,transparent,red 20%,red 80%,transparent)");
assert_parse!(
CssAtomSet::ATOMS,
Gradient,
"radial-gradient(closest-corner circle,rgba(1,65,255,0.4),rgba(1,65,255,0))"
);
}
}