css_ast/functions/
transform_functions.rs

1use super::prelude::*;
2use crate::{AngleOrZero, Length, LengthPercentage, NoneOr, NumberOrPercentage};
3
4// https://drafts.csswg.org/css-transforms-1/#two-d-transform-functions
5#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
6#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
7#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
8#[derive(csskit_derives::NodeWithMetadata)]
9#[allow(clippy::large_enum_variant)] // TODO: matrix3d should probably be boxed
10pub enum TransformFunction {
11	Matrix(MatrixFunction),
12	Matrix3d(Matrix3dFunction),
13	Translate(TranslateFunction),
14	Translate3d(Translate3dFunction),
15	TranslateX(TranslatexFunction),
16	TranslateY(TranslateyFunction),
17	TranslateZ(TranslatezFunction),
18	Scale(ScaleFunction),
19	Scale3d(Scale3dFunction),
20	ScaleX(ScalexFunction),
21	ScaleY(ScaleyFunction),
22	ScaleZ(ScalezFunction),
23	Rotate(RotateFunction),
24	Rotate3d(Rotate3dFunction),
25	RotateX(RotatexFunction),
26	RotateY(RotateyFunction),
27	RotateZ(RotatezFunction),
28	Skew(SkewFunction),
29	SkewX(SkewxFunction),
30	SkewY(SkewyFunction),
31	Perspective(PerspectiveFunction),
32}
33
34/// <https://drafts.csswg.org/css-transforms-1/#funcdef-transform-matrix>
35///
36/// ```text,ignore
37/// matrix() = matrix( <number>#{6} )
38/// ```
39#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
40#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
41#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
42#[derive(csskit_derives::NodeWithMetadata)]
43pub struct MatrixFunction {
44	#[atom(CssAtomSet::Matrix)]
45	pub name: T![Function],
46	pub params: MatrixFunctionParams,
47	pub close: T![')'],
48}
49
50#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
51#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
52pub struct MatrixFunctionParams(
53	pub T![Number],
54	pub Option<T![,]>,
55	pub T![Number],
56	pub Option<T![,]>,
57	pub T![Number],
58	pub Option<T![,]>,
59	pub T![Number],
60	pub Option<T![,]>,
61	pub T![Number],
62	pub Option<T![,]>,
63	pub T![Number],
64);
65
66/// <https://drafts.csswg.org/css-transforms-2/#funcdef-matrix3d>
67///
68/// ```text,ignore
69/// matrix3d() = matrix3d( <number>#{16} )
70/// ```
71#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
72#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
73#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
74#[derive(csskit_derives::NodeWithMetadata)]
75pub struct Matrix3dFunction {
76	#[atom(CssAtomSet::Matrix3d)]
77	pub name: T![Function],
78	pub params: Matrix3dFunctionParams,
79	pub close: T![')'],
80}
81
82#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
83#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
84#[allow(clippy::type_complexity)] // TODO: simplify types
85pub struct Matrix3dFunctionParams(
86	pub T![Number],
87	pub Option<T![,]>,
88	pub T![Number],
89	pub Option<T![,]>,
90	pub T![Number],
91	pub Option<T![,]>,
92	pub T![Number],
93	pub Option<T![,]>,
94	pub T![Number],
95	pub Option<T![,]>,
96	pub T![Number],
97	pub Option<T![,]>,
98	pub T![Number],
99	pub Option<T![,]>,
100	pub T![Number],
101	pub Option<T![,]>,
102	pub T![Number],
103	pub Option<T![,]>,
104	pub T![Number],
105	pub Option<T![,]>,
106	pub T![Number],
107	pub Option<T![,]>,
108	pub T![Number],
109	pub Option<T![,]>,
110	pub T![Number],
111	pub Option<T![,]>,
112	pub T![Number],
113	pub Option<T![,]>,
114	pub T![Number],
115	pub Option<T![,]>,
116	pub T![Number],
117);
118
119/// <https://drafts.csswg.org/css-transforms-1/#funcdef-transform-translate>
120///
121/// ```text,ignore
122/// translate() = translate( <length-percentage> , <length-percentage>? )
123/// ```
124#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
125#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
126#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
127#[derive(csskit_derives::NodeWithMetadata)]
128pub struct TranslateFunction {
129	#[atom(CssAtomSet::Translate)]
130	pub name: T![Function],
131	pub x: LengthPercentage,
132	pub comma: Option<T![,]>,
133	pub y: Option<LengthPercentage>,
134	pub close: T![')'],
135}
136
137/// <https://drafts.csswg.org/css-transforms-2/#funcdef-translate3d>
138///
139/// ```text,ignore
140/// translate3d() = translate3d( <length-percentage> , <length-percentage> , <length> )
141/// ```
142#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
143#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
144#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
145#[derive(csskit_derives::NodeWithMetadata)]
146pub struct Translate3dFunction {
147	#[atom(CssAtomSet::Translate3d)]
148	pub name: T![Function],
149	pub params: Translate3dFunctionParams,
150	pub close: T![')'],
151}
152
153#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
154#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
155pub struct Translate3dFunctionParams(
156	pub LengthPercentage,
157	pub Option<T![,]>,
158	pub LengthPercentage,
159	pub Option<T![,]>,
160	pub Length,
161);
162
163/// <https://drafts.csswg.org/css-transforms-1/#funcdef-transform-translatex>
164///
165/// ```text,ignore
166/// translateX() = translateX( <length-percentage> )
167/// ```
168#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
169#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
170#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
171#[derive(csskit_derives::NodeWithMetadata)]
172pub struct TranslatexFunction {
173	#[atom(CssAtomSet::Translatex)]
174	pub name: T![Function],
175	pub params: LengthPercentage,
176	pub close: T![')'],
177}
178
179/// <https://drafts.csswg.org/css-transforms-1/#funcdef-transform-translatey>
180///
181/// ```text,ignore
182/// translateY() = translateY( <length-percentage> )
183/// ```
184#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
185#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
186#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
187#[derive(csskit_derives::NodeWithMetadata)]
188pub struct TranslateyFunction {
189	#[atom(CssAtomSet::Translatey)]
190	pub name: T![Function],
191	pub params: LengthPercentage,
192	pub close: T![')'],
193}
194
195/// <https://drafts.csswg.org/css-transforms-2/#funcdef-translatez>
196///
197/// ```text,ignore
198/// translateZ() = translateZ( <length> )
199/// ```
200#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
201#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
202#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
203#[derive(csskit_derives::NodeWithMetadata)]
204pub struct TranslatezFunction {
205	#[atom(CssAtomSet::Translatez)]
206	pub name: T![Function],
207	pub params: Length,
208	pub close: T![')'],
209}
210
211/// <https://drafts.csswg.org/css-transforms-2/#funcdef-scale>
212///
213/// ```text,ignore
214/// scale() = scale( [ <number> | <percentage> ]#{1,2} )
215/// ```
216#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
217#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
218#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
219#[derive(csskit_derives::NodeWithMetadata)]
220pub struct ScaleFunction {
221	#[atom(CssAtomSet::Scale)]
222	pub name: T![Function],
223	pub params: (NumberOrPercentage, Option<T![,]>, Option<NumberOrPercentage>),
224	pub close: T![')'],
225}
226
227/// <https://drafts.csswg.org/css-transforms-2/#funcdef-scale3d>
228///
229/// ```text,ignore
230/// scale3d() = scale3d( [ <number> | <percentage> ]#{3} )
231/// ```
232#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
233#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
234#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
235#[derive(csskit_derives::NodeWithMetadata)]
236pub struct Scale3dFunction {
237	#[atom(CssAtomSet::Scale3d)]
238	pub name: T![Function],
239	pub params: Scale3dFunctionParams,
240	pub close: T![')'],
241}
242
243#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
244#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
245pub struct Scale3dFunctionParams(
246	pub NumberOrPercentage,
247	pub Option<T![,]>,
248	pub NumberOrPercentage,
249	pub Option<T![,]>,
250	pub NumberOrPercentage,
251);
252
253/// <https://drafts.csswg.org/css-transforms-2/#funcdef-scalex>
254///
255/// ```text,ignore
256/// scaleX() = scaleX( <number> | <percentage> )
257/// ````
258#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
259#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
260#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
261#[derive(csskit_derives::NodeWithMetadata)]
262pub struct ScalexFunction {
263	#[atom(CssAtomSet::Scalex)]
264	pub name: T![Function],
265	pub params: NumberOrPercentage,
266	pub close: T![')'],
267}
268
269/// <https://drafts.csswg.org/css-transforms-2/#funcdef-scaley>
270///
271/// ```text,ignore
272/// scaleY() = scaleY( <number> | <percentage> )
273/// ````
274#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
275#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
276#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
277#[derive(csskit_derives::NodeWithMetadata)]
278pub struct ScaleyFunction {
279	#[atom(CssAtomSet::Scaley)]
280	pub name: T![Function],
281	pub params: NumberOrPercentage,
282	pub close: T![')'],
283}
284
285/// <https://drafts.csswg.org/css-transforms-2/#funcdef-scalez>
286///
287/// ```text,ignore
288/// scaleZ() = scaleZ( <number> | <percentage> )
289/// ````
290#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
291#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
292#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
293#[derive(csskit_derives::NodeWithMetadata)]
294pub struct ScalezFunction {
295	#[atom(CssAtomSet::Scalez)]
296	pub name: T![Function],
297	pub params: NumberOrPercentage,
298	pub close: T![')'],
299}
300
301/// <https://drafts.csswg.org/css-transforms-1/#funcdef-transform-rotate>
302///
303/// ```text,ignore
304/// rotate() = rotate( [ <angle> | <zero> ] )
305/// ```
306#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
307#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
308#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
309#[derive(csskit_derives::NodeWithMetadata)]
310pub struct RotateFunction {
311	#[atom(CssAtomSet::Rotate)]
312	pub name: T![Function],
313	pub params: AngleOrZero,
314	pub close: T![')'],
315}
316
317/// <https://drafts.csswg.org/css-transforms-2/#funcdef-rotate3d>
318///
319/// ```text,ignore
320/// rotate3d() = rotate3d( <number> , <number> , <number> , [ <angle> | <zero> ] )
321/// ```
322#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
323#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
324#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
325#[derive(csskit_derives::NodeWithMetadata)]
326pub struct Rotate3dFunction {
327	#[atom(CssAtomSet::Rotate3d)]
328	pub name: T![Function],
329	pub params: Rotate3dFunctionParams,
330	pub close: T![')'],
331}
332
333#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
334#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
335pub struct Rotate3dFunctionParams(
336	pub T![Number],
337	pub Option<T![,]>,
338	pub T![Number],
339	pub Option<T![,]>,
340	pub T![Number],
341	pub Option<T![,]>,
342	pub AngleOrZero,
343);
344
345/// <https://drafts.csswg.org/css-transforms-2/#funcdef-rotatex>
346///
347/// ```text,ignore
348/// rotateX() = rotateX( [ <angle> | <zero> ] )
349/// ```
350#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
351#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
352#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
353#[derive(csskit_derives::NodeWithMetadata)]
354pub struct RotatexFunction {
355	#[atom(CssAtomSet::Rotatex)]
356	pub name: T![Function],
357	pub params: AngleOrZero,
358	pub close: T![')'],
359}
360
361/// <https://drafts.csswg.org/css-transforms-2/#funcdef-rotatey>
362///
363/// ```text,ignore
364/// rotateY() = rotateY( [ <angle> | <zero> ] )
365/// ```
366#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
367#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
368#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
369#[derive(csskit_derives::NodeWithMetadata)]
370pub struct RotateyFunction {
371	#[atom(CssAtomSet::Rotatey)]
372	pub name: T![Function],
373	pub params: AngleOrZero,
374	pub close: T![')'],
375}
376
377/// <https://drafts.csswg.org/css-transforms-2/#funcdef-rotatez>
378///
379/// ```text,ignore
380/// rotateZ() = rotateZ( [ <angle> | <zero> ] )
381/// ```
382#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
383#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
384#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
385#[derive(csskit_derives::NodeWithMetadata)]
386pub struct RotatezFunction {
387	#[atom(CssAtomSet::Rotatez)]
388	pub name: T![Function],
389	pub params: AngleOrZero,
390	pub close: T![')'],
391}
392
393/// <https://drafts.csswg.org/css-transforms-1/#funcdef-transform-skew>
394///
395/// ```text,ignore
396/// skew() = skew( [ <angle> | <zero> ] , [ <angle> | <zero> ]? )
397/// ```
398#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
399#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
400#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
401#[derive(csskit_derives::NodeWithMetadata)]
402pub struct SkewFunction {
403	#[atom(CssAtomSet::Skew)]
404	pub name: T![Function],
405	pub params: (AngleOrZero, Option<T![,]>, Option<AngleOrZero>),
406	pub close: T![')'],
407}
408
409/// <https://drafts.csswg.org/css-transforms-1/#funcdef-transform-skewx>
410///
411/// ```text,ignore
412/// skewX() = skewX( [ <angle> | <zero> ] )
413/// ```
414#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
415#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
416#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
417#[derive(csskit_derives::NodeWithMetadata)]
418pub struct SkewxFunction {
419	#[atom(CssAtomSet::Skewx)]
420	pub name: T![Function],
421	pub params: AngleOrZero,
422	pub close: T![')'],
423}
424
425/// <https://drafts.csswg.org/css-transforms-1/#funcdef-transform-skewy>
426///
427/// ```text,ignore
428/// skewY() = skewY( [ <angle> | <zero> ] )
429/// ```
430#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
431#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
432#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
433#[derive(csskit_derives::NodeWithMetadata)]
434pub struct SkewyFunction {
435	#[atom(CssAtomSet::Skewy)]
436	pub name: T![Function],
437	pub params: AngleOrZero,
438	pub close: T![')'],
439}
440
441/// <https://drafts.csswg.org/css-transforms-2/#funcdef-perspective>
442///
443/// ```text,ignore
444/// perspective() = perspective( [ <length [0,∞]> | none ] )
445/// ```
446#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
447#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
448#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
449#[derive(csskit_derives::NodeWithMetadata)]
450pub struct PerspectiveFunction {
451	#[atom(CssAtomSet::Perspective)]
452	pub name: T![Function],
453	pub params: NoneOr<Length>,
454	pub close: T![')'],
455}
456
457#[cfg(test)]
458mod tests {
459	use super::*;
460	use crate::CssAtomSet;
461	use css_parse::{assert_parse, assert_parse_error, assert_parse_span};
462
463	#[test]
464	fn size_test() {
465		assert_eq!(std::mem::size_of::<TransformFunction>(), 456);
466	}
467
468	#[test]
469	fn test_writes() {
470		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "matrix(1,2,3,4,5,6)");
471		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "matrix(1 2 3 4 5 6)");
472		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "matrix(0,0,0,0,0,0)");
473		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "matrix(-1,-2,-3,-4,-5,-6)");
474		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "matrix(1.5,2.5,3.5,4.5,5.5,6.5)");
475
476		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "translate(10px)");
477		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "translate(10px,20px)");
478		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "translate(45%)");
479		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "translate(2rem)");
480		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "translateX(1rem)");
481		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "translateY(1rem)");
482
483		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "scale(1,2)");
484		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "scale(0,0)");
485		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "scale(1)");
486		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "scale(1.5,2.5)");
487		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "scaleX(2)");
488		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "scaleY(2)");
489
490		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "rotate(45deg)");
491		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "rotate(0)");
492		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "rotate(2turn)");
493		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "rotate(20rad)");
494
495		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "skew(1deg,2deg)");
496		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "skew(0,0)");
497		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "skew(1deg)");
498		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "skewX(1deg)");
499		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "skewX(0)");
500		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "skewY(1deg)");
501		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "skewY(0)");
502
503		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "scale3d(10%,10%,10%)");
504		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "rotate3d(1,2,3,10deg)");
505	}
506
507	#[test]
508	fn test_span() {
509		assert_parse_span!(
510			CssAtomSet::ATOMS,
511			TransformFunction,
512			r#"
513				matrix(1,2,3,4,5,6) translate(0)
514				^^^^^^^^^^^^^^^^^^^
515		"#
516		);
517		assert_parse_span!(
518			CssAtomSet::ATOMS,
519			TransformFunction,
520			r#"
521				translate(0) foo
522				^^^^^^^^^^^^
523		"#
524		);
525		assert_parse_span!(
526			CssAtomSet::ATOMS,
527			TranslateFunction,
528			r#"
529				translate(0) bar
530				^^^^^^^^^^^^
531		"#
532		);
533	}
534
535	#[test]
536	fn test_errors() {
537		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "matrix()");
538		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "matrix(1)");
539		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "matrix(1,2)");
540		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "matrix(one,two,three,four,five,size)");
541
542		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "translate()");
543		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "translate(foo)");
544		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "translateX()");
545		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "translateX(foo)");
546		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "translateY()");
547		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "translateY(foo)");
548
549		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "scale()");
550		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "scale(foo)");
551		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "scaleX()");
552		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "scaleX(foo)");
553		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "scaleY()");
554		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "scaleY(foo)");
555
556		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "rotate()");
557		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "rotate(45px)");
558		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "rotate(all the way around)");
559
560		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "skew()");
561		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "skew(foo)");
562		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "skewX()");
563		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "skewX(foo)");
564		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "skewY()");
565		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "skewY(foo)");
566	}
567}