1use super::prelude::*;
2use crate::{Length, LengthPercentage};
3
4#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
10#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
11pub enum Gradient<'a> {
12 #[atom(CssAtomSet::LinearGradient)]
13 LinearGradientFunction(LinearGradientFunction<'a>),
14 #[atom(CssAtomSet::RepeatingLinearGradient)]
15 RepeatingLinearGradientFunction(RepeatingLinearGradientFunction<'a>),
16 #[atom(CssAtomSet::RadialGradient)]
17 RadialGradientFunction(RadialGradientFunction<'a>),
18 #[atom(CssAtomSet::RepeatingRadialGradient)]
19 RepeatingRadialGradientFunction(RepeatingRadialGradientFunction<'a>),
20}
21
22#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
29#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
30#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
31pub struct LinearGradientFunction<'a> {
32 #[atom(CssAtomSet::LinearGradient)]
33 pub name: T![Function],
34 pub params: LinearGradientFunctionParams<'a>,
35 pub close: T![')'],
36}
37
38#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
39#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
40pub struct LinearGradientFunctionParams<'a>(
41 Option<LinearDirection>,
42 Option<T![,]>,
43 CommaSeparated<'a, ColorStopOrHint>,
44);
45
46#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
53#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
54#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
55pub struct RepeatingLinearGradientFunction<'a> {
56 #[atom(CssAtomSet::RepeatingLinearGradient)]
57 pub name: T![Function],
58 pub params: RepeatingLinearGradientFunctionParams<'a>,
59 pub close: T![')'],
60}
61
62#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
63#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
64pub struct RepeatingLinearGradientFunctionParams<'a>(
65 Option<LinearDirection>,
66 Option<T![,]>,
67 CommaSeparated<'a, ColorStopOrHint>,
68);
69
70#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
79#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
80#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
81pub struct RadialGradientFunction<'a> {
82 #[atom(CssAtomSet::RadialGradient)]
83 pub name: T![Function],
84 pub params: RadialGradientFunctionParams<'a>,
85 pub close: T![')'],
86}
87
88#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
89#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
90pub struct RadialGradientFunctionParams<'a>(
91 Option<RadialSize>,
92 Option<RadialShape>,
93 Option<T![Ident]>,
94 Option<Position>,
95 Option<T![,]>,
96 CommaSeparated<'a, ColorStopOrHint>,
97);
98
99#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
108#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
109#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
110pub struct RepeatingRadialGradientFunction<'a> {
111 #[atom(CssAtomSet::RepeatingRadialGradient)]
112 pub name: T![Function],
113 pub params: RepeatingRadialGradientFunctionParams<'a>,
114 pub close: T![')'],
115}
116
117#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
118#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
119pub struct RepeatingRadialGradientFunctionParams<'a>(
120 Option<RadialSize>,
121 Option<RadialShape>,
122 Option<T![Ident]>,
123 Option<Position>,
124 Option<T![,]>,
125 CommaSeparated<'a, ColorStopOrHint>,
126);
127
128#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable))]
129#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
130#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
131#[cfg_attr(feature = "visitable", visit(skip))]
132pub enum NamedDirection {
133 #[atom(CssAtomSet::Bottom)]
134 Bottom(T![Ident]),
135 #[atom(CssAtomSet::Top)]
136 Top(T![Ident]),
137 #[atom(CssAtomSet::Left)]
138 Left(T![Ident]),
139 #[atom(CssAtomSet::Right)]
140 Right(T![Ident]),
141}
142
143#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
144#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
145pub enum LinearDirection {
146 Angle(Angle),
147 Named(#[atom(CssAtomSet::To)] T![Ident], NamedDirection, Option<NamedDirection>),
148}
149
150#[derive(Peek, ToSpan, ToCursors, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
157#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
158pub enum RadialSize {
159 Extent(RadialExtent),
160 Circular(Length),
161 Elliptical(LengthPercentage, LengthPercentage),
162}
163
164#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable))]
170#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
171#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
172#[cfg_attr(feature = "visitable", visit(skip))]
173pub enum RadialExtent {
174 #[atom(CssAtomSet::ClosestCorner)]
175 ClosestCorner(T![Ident]),
176 #[atom(CssAtomSet::ClosestSide)]
177 ClosestSide(T![Ident]),
178 #[atom(CssAtomSet::FarthestCorner)]
179 FarthestCorner(T![Ident]),
180 #[atom(CssAtomSet::FarthestSide)]
181 FarthestSide(T![Ident]),
182}
183
184impl<'a> Parse<'a> for RadialSize {
185 fn parse<I>(p: &mut Parser<'a, I>) -> ParserResult<Self>
186 where
187 I: Iterator<Item = Cursor> + Clone,
188 {
189 if let Some(extent) = p.parse_if_peek::<RadialExtent>()? {
190 return Ok(RadialSize::Extent(extent));
191 }
192 if p.peek::<Length>() {
193 let first_len = p.parse::<LengthPercentage>()?;
194 if !p.peek::<Length>()
195 && let LengthPercentage::Length(len) = first_len
196 {
197 return Ok(Self::Circular(len));
198 }
199 let second_len = p.parse::<LengthPercentage>()?;
200 return Ok(Self::Elliptical(first_len, second_len));
201 }
202 let first = p.parse::<LengthPercentage>()?;
203 let second = p.parse::<LengthPercentage>()?;
204 Ok(Self::Elliptical(first, second))
205 }
206}
207
208#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable))]
214#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
215#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
216#[cfg_attr(feature = "visitable", visit(skip))]
217pub enum RadialShape {
218 #[atom(CssAtomSet::Circle)]
219 Circle(T![Ident]),
220 #[atom(CssAtomSet::Ellipse)]
221 Ellipse(T![Ident]),
222}
223
224#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
225#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
226pub enum ColorStopOrHint {
227 Hint(LengthPercentage),
228 Stop(Color, Option<LengthPercentage>),
229}
230
231#[cfg(test)]
232mod tests {
233 use super::*;
234 use crate::CssAtomSet;
235 use css_parse::assert_parse;
236
237 #[test]
238 fn size_test() {
239 assert_eq!(std::mem::size_of::<Gradient>(), 208);
240 assert_eq!(std::mem::size_of::<LinearDirection>(), 44);
241 assert_eq!(std::mem::size_of::<RadialSize>(), 32);
242 assert_eq!(std::mem::size_of::<ColorStopOrHint>(), 156);
243 }
244
245 #[test]
246 fn test_writes() {
247 assert_parse!(CssAtomSet::ATOMS, Gradient, "linear-gradient(to bottom,yellow,blue)");
248 assert_parse!(CssAtomSet::ATOMS, Gradient, "linear-gradient(yellow,blue)");
249 assert_parse!(CssAtomSet::ATOMS, Gradient, "linear-gradient(to bottom,#fff,#fff 85%,#e6e6e6)");
250 assert_parse!(CssAtomSet::ATOMS, Gradient, "linear-gradient(45deg,#808080 25%,transparent 25%)");
251 assert_parse!(CssAtomSet::ATOMS, Gradient, "linear-gradient(to right,transparent,red 20%,red 80%,transparent)");
252 assert_parse!(
253 CssAtomSet::ATOMS,
254 Gradient,
255 "radial-gradient(closest-corner circle,rgba(1,65,255,0.4),rgba(1,65,255,0))"
256 );
257 }
258}