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