1use super::prelude::*;
2use crate::{AngleOrZero, Color, Length, NonNegative, NumberOrPercentage, Url};
3
4#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
13#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
14#[derive(csskit_derives::NodeWithMetadata)]
15pub enum FilterFunction<'a> {
16 #[atom(CssAtomSet::Blur)]
17 Blur(BlurFunction),
18 #[atom(CssAtomSet::Brightness)]
19 Brightness(BrightnessFunction),
20 #[atom(CssAtomSet::Contrast)]
21 Contrast(ContrastFunction),
22 #[atom(CssAtomSet::DropShadow)]
23 DropShadow(DropShadowFunction<'a>),
24 #[atom(CssAtomSet::Grayscale)]
25 Grayscale(GrayscaleFunction),
26 #[atom(CssAtomSet::HueRotate)]
27 HueRotate(HueRotateFunction),
28 #[atom(CssAtomSet::Invert)]
29 Invert(InvertFunction),
30 #[atom(CssAtomSet::Opacity)]
31 Opacity(OpacityFunction),
32 #[atom(CssAtomSet::Saturate)]
33 Saturate(SaturateFunction),
34 #[atom(CssAtomSet::Sepia)]
35 Sepia(SepiaFunction),
36}
37
38#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
44#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
45#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
46#[derive(csskit_derives::NodeWithMetadata)]
47pub struct FilterValueList<'a>(pub Vec<'a, FilterValue<'a>>);
48
49#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
51#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
52#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
53#[derive(csskit_derives::NodeWithMetadata)]
54pub enum FilterValue<'a> {
55 FilterFunction(FilterFunction<'a>),
56 Url(Url),
57}
58
59#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
61#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
62#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
63#[derive(csskit_derives::NodeWithMetadata)]
64pub struct BlurFunction {
65 #[atom(CssAtomSet::Blur)]
66 pub name: T![Function],
67 pub radius: Option<NonNegative<Length>>,
68 pub close: T![')'],
69}
70
71#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
73#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
74#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
75#[derive(csskit_derives::NodeWithMetadata)]
76pub struct BrightnessFunction {
77 #[atom(CssAtomSet::Brightness)]
78 pub name: T![Function],
79 pub value: Option<NumberOrPercentage>,
80 pub close: T![')'],
81}
82
83#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
85#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
86#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
87#[derive(csskit_derives::NodeWithMetadata)]
88pub struct ContrastFunction {
89 #[atom(CssAtomSet::Contrast)]
90 pub name: T![Function],
91 pub value: Option<NumberOrPercentage>,
92 pub close: T![')'],
93}
94
95#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
99#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
100#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
101#[derive(csskit_derives::NodeWithMetadata)]
102pub struct DropShadowFunction<'a> {
103 #[atom(CssAtomSet::DropShadow)]
104 pub name: T![Function],
105 pub color: Option<Color<'a>>,
106 pub offset_x: Length,
107 pub offset_y: Length,
108 pub blur_radius: Option<NonNegative<Length>>,
109 pub close: T![')'],
110}
111
112#[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 GrayscaleFunction {
118 #[atom(CssAtomSet::Grayscale)]
119 pub name: T![Function],
120 pub value: Option<NumberOrPercentage>,
121 pub close: T![')'],
122}
123
124#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
126#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
127#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
128#[derive(csskit_derives::NodeWithMetadata)]
129pub struct HueRotateFunction {
130 #[atom(CssAtomSet::HueRotate)]
131 pub name: T![Function],
132 pub angle: Option<AngleOrZero>,
133 pub close: T![')'],
134}
135
136#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
138#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
139#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
140#[derive(csskit_derives::NodeWithMetadata)]
141pub struct InvertFunction {
142 #[atom(CssAtomSet::Invert)]
143 pub name: T![Function],
144 pub value: Option<NumberOrPercentage>,
145 pub close: T![')'],
146}
147
148#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
150#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
151#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
152#[derive(csskit_derives::NodeWithMetadata)]
153pub struct OpacityFunction {
154 #[atom(CssAtomSet::Opacity)]
155 pub name: T![Function],
156 pub value: Option<NumberOrPercentage>,
157 pub close: T![')'],
158}
159
160#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
162#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
163#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
164#[derive(csskit_derives::NodeWithMetadata)]
165pub struct SaturateFunction {
166 #[atom(CssAtomSet::Saturate)]
167 pub name: T![Function],
168 pub value: Option<NumberOrPercentage>,
169 pub close: T![')'],
170}
171
172#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
174#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
175#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
176#[derive(csskit_derives::NodeWithMetadata)]
177pub struct SepiaFunction {
178 #[atom(CssAtomSet::Sepia)]
179 pub name: T![Function],
180 pub value: Option<NumberOrPercentage>,
181 pub close: T![')'],
182}
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187 use crate::CssAtomSet;
188 use css_parse::{assert_parse, assert_parse_error};
189
190 #[test]
191 fn size_test() {
192 assert_eq!(std::mem::size_of::<FilterFunction>(), 96);
193 }
194
195 #[test]
196 fn test_filter_function_parses() {
197 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "blur()");
198 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "blur(5px)");
199 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "brightness(0.5)");
200 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "brightness(50%)");
201 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "contrast(2)");
202 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "contrast(200%)");
203 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "drop-shadow(2px 4px)");
204 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "drop-shadow(2px 4px 3px)");
205 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "drop-shadow(red 2px 4px)");
206 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "drop-shadow(red 2px 4px 5px)");
207 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "grayscale(1)");
208 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "grayscale(100%)");
209 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "hue-rotate(90deg)");
210 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "hue-rotate(0)");
211 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "invert(0.5)");
212 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "invert(50%)");
213 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "opacity(0.5)");
214 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "opacity(50%)");
215 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "saturate(2)");
216 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "saturate(200%)");
217 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "sepia(0.5)");
218 assert_parse!(CssAtomSet::ATOMS, FilterFunction, "sepia(50%)");
219 }
220
221 #[test]
222 fn test_filter_function_errors() {
223 assert_parse_error!(CssAtomSet::ATOMS, FilterFunction, "none");
224 assert_parse_error!(CssAtomSet::ATOMS, FilterFunction, "foo()");
225 assert_parse_error!(CssAtomSet::ATOMS, FilterFunction, "blur(-5px)");
226 }
227
228 #[test]
229 fn test_filter_value_list_parses() {
230 assert_parse!(CssAtomSet::ATOMS, FilterValueList, "blur(5px)");
231 assert_parse!(CssAtomSet::ATOMS, FilterValueList, "blur(5px)brightness(0.5)");
232 assert_parse!(CssAtomSet::ATOMS, FilterValueList, "blur(5px)contrast(200%)grayscale(0.5)");
233 assert_parse!(CssAtomSet::ATOMS, FilterValueList, "url(\"filter.svg\")");
234 }
235
236 #[test]
237 fn test_filter_value_list_errors() {
238 assert_parse_error!(CssAtomSet::ATOMS, FilterValueList, "none");
239 }
240}