Skip to main content

css_ast/functions/
transform_functions.rs

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