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