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	#[semantic_eq(skip)]
247	pub params: (NumericValue<'a, NumberOrPercentage>, Option<T![,]>, Option<NumericValue<'a, NumberOrPercentage>>),
248	#[semantic_eq(skip)]
249	pub close: T![')'],
250}
251
252/// <https://drafts.csswg.org/css-transforms-2/#funcdef-scale3d>
253///
254/// ```text,ignore
255/// scale3d() = scale3d( [ <number> | <percentage> ]#{3} )
256/// ```
257#[node]
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 Scale3dFunction<'a> {
263	#[atom(CssAtomSet::Scale3d)]
264	pub name: T![Function],
265	pub params: Scale3dFunctionParams<'a>,
266	#[semantic_eq(skip)]
267	pub close: T![')'],
268}
269
270#[node]
271#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
272#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
273#[derive(csskit_derives::NodeWithMetadata)]
274pub struct Scale3dFunctionParams<'a>(
275	pub NumericValue<'a, NumberOrPercentage>,
276	#[semantic_eq(skip)] pub Option<T![,]>,
277	pub NumericValue<'a, NumberOrPercentage>,
278	#[semantic_eq(skip)] pub Option<T![,]>,
279	pub NumericValue<'a, NumberOrPercentage>,
280);
281
282/// <https://drafts.csswg.org/css-transforms-2/#funcdef-scalex>
283///
284/// ```text,ignore
285/// scaleX() = scaleX( <number> | <percentage> )
286/// ````
287#[node]
288#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
289#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
290#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
291#[derive(csskit_derives::NodeWithMetadata)]
292pub struct ScalexFunction<'a> {
293	#[atom(CssAtomSet::Scalex)]
294	pub name: T![Function],
295	pub params: NumericValue<'a, NumberOrPercentage>,
296	#[semantic_eq(skip)]
297	pub close: T![')'],
298}
299
300/// <https://drafts.csswg.org/css-transforms-2/#funcdef-scaley>
301///
302/// ```text,ignore
303/// scaleY() = scaleY( <number> | <percentage> )
304/// ````
305#[node]
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 ScaleyFunction<'a> {
311	#[atom(CssAtomSet::Scaley)]
312	pub name: T![Function],
313	pub params: NumericValue<'a, NumberOrPercentage>,
314	#[semantic_eq(skip)]
315	pub close: T![')'],
316}
317
318/// <https://drafts.csswg.org/css-transforms-2/#funcdef-scalez>
319///
320/// ```text,ignore
321/// scaleZ() = scaleZ( <number> | <percentage> )
322/// ````
323#[node]
324#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
325#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
326#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
327#[derive(csskit_derives::NodeWithMetadata)]
328pub struct ScalezFunction<'a> {
329	#[atom(CssAtomSet::Scalez)]
330	pub name: T![Function],
331	pub params: NumericValue<'a, NumberOrPercentage>,
332	#[semantic_eq(skip)]
333	pub close: T![')'],
334}
335
336/// <https://drafts.csswg.org/css-transforms-1/#funcdef-transform-rotate>
337///
338/// ```text,ignore
339/// rotate() = rotate( [ <angle> | <zero> ] )
340/// ```
341#[node]
342#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
343#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
344#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
345#[derive(csskit_derives::NodeWithMetadata)]
346pub struct RotateFunction<'a> {
347	#[atom(CssAtomSet::Rotate)]
348	pub name: T![Function],
349	pub params: CalcableValue<'a, AngleOrZero>,
350	#[semantic_eq(skip)]
351	pub close: T![')'],
352}
353
354/// <https://drafts.csswg.org/css-transforms-2/#funcdef-rotate3d>
355///
356/// ```text,ignore
357/// rotate3d() = rotate3d( <number> , <number> , <number> , [ <angle> | <zero> ] )
358/// ```
359#[node]
360#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
361#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
362#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
363#[derive(csskit_derives::NodeWithMetadata)]
364pub struct Rotate3dFunction<'a> {
365	#[atom(CssAtomSet::Rotate3d)]
366	pub name: T![Function],
367	pub params: Rotate3dFunctionParams<'a>,
368	#[semantic_eq(skip)]
369	pub close: T![')'],
370}
371
372#[node]
373#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
374#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
375#[derive(csskit_derives::NodeWithMetadata)]
376pub struct Rotate3dFunctionParams<'a>(
377	pub NumericValue<'a, T![Number]>,
378	#[semantic_eq(skip)] pub Option<T![,]>,
379	pub NumericValue<'a, T![Number]>,
380	#[semantic_eq(skip)] pub Option<T![,]>,
381	pub NumericValue<'a, T![Number]>,
382	#[semantic_eq(skip)] pub Option<T![,]>,
383	pub CalcableValue<'a, AngleOrZero>,
384);
385
386/// <https://drafts.csswg.org/css-transforms-2/#funcdef-rotatex>
387///
388/// ```text,ignore
389/// rotateX() = rotateX( [ <angle> | <zero> ] )
390/// ```
391#[node]
392#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
393#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
394#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
395#[derive(csskit_derives::NodeWithMetadata)]
396pub struct RotatexFunction<'a> {
397	#[atom(CssAtomSet::Rotatex)]
398	pub name: T![Function],
399	pub params: CalcableValue<'a, AngleOrZero>,
400	#[semantic_eq(skip)]
401	pub close: T![')'],
402}
403
404/// <https://drafts.csswg.org/css-transforms-2/#funcdef-rotatey>
405///
406/// ```text,ignore
407/// rotateY() = rotateY( [ <angle> | <zero> ] )
408/// ```
409#[node]
410#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
411#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
412#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
413#[derive(csskit_derives::NodeWithMetadata)]
414pub struct RotateyFunction<'a> {
415	#[atom(CssAtomSet::Rotatey)]
416	pub name: T![Function],
417	pub params: CalcableValue<'a, AngleOrZero>,
418	#[semantic_eq(skip)]
419	pub close: T![')'],
420}
421
422/// <https://drafts.csswg.org/css-transforms-2/#funcdef-rotatez>
423///
424/// ```text,ignore
425/// rotateZ() = rotateZ( [ <angle> | <zero> ] )
426/// ```
427#[node]
428#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
429#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
430#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
431#[derive(csskit_derives::NodeWithMetadata)]
432pub struct RotatezFunction<'a> {
433	#[atom(CssAtomSet::Rotatez)]
434	pub name: T![Function],
435	pub params: CalcableValue<'a, AngleOrZero>,
436	#[semantic_eq(skip)]
437	pub close: T![')'],
438}
439
440/// <https://drafts.csswg.org/css-transforms-1/#funcdef-transform-skew>
441///
442/// ```text,ignore
443/// skew() = skew( [ <angle> | <zero> ] , [ <angle> | <zero> ]? )
444/// ```
445#[node]
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 SkewFunction<'a> {
451	#[atom(CssAtomSet::Skew)]
452	pub name: T![Function],
453	#[semantic_eq(skip)]
454	pub params: (CalcableValue<'a, AngleOrZero>, Option<T![,]>, Option<CalcableValue<'a, AngleOrZero>>),
455	#[semantic_eq(skip)]
456	pub close: T![')'],
457}
458
459/// <https://drafts.csswg.org/css-transforms-1/#funcdef-transform-skewx>
460///
461/// ```text,ignore
462/// skewX() = skewX( [ <angle> | <zero> ] )
463/// ```
464#[node]
465#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
466#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
467#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
468#[derive(csskit_derives::NodeWithMetadata)]
469pub struct SkewxFunction<'a> {
470	#[atom(CssAtomSet::Skewx)]
471	pub name: T![Function],
472	pub params: CalcableValue<'a, AngleOrZero>,
473	#[semantic_eq(skip)]
474	pub close: T![')'],
475}
476
477/// <https://drafts.csswg.org/css-transforms-1/#funcdef-transform-skewy>
478///
479/// ```text,ignore
480/// skewY() = skewY( [ <angle> | <zero> ] )
481/// ```
482#[node]
483#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
484#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
485#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
486#[derive(csskit_derives::NodeWithMetadata)]
487pub struct SkewyFunction<'a> {
488	#[atom(CssAtomSet::Skewy)]
489	pub name: T![Function],
490	pub params: CalcableValue<'a, AngleOrZero>,
491	#[semantic_eq(skip)]
492	pub close: T![')'],
493}
494
495/// <https://drafts.csswg.org/css-transforms-2/#funcdef-perspective>
496///
497/// ```text,ignore
498/// perspective() = perspective( [ <length [0,∞]> | none ] )
499/// ```
500#[node]
501#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
502#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
503#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
504#[derive(csskit_derives::NodeWithMetadata)]
505pub struct PerspectiveFunction<'a> {
506	#[atom(CssAtomSet::Perspective)]
507	pub name: T![Function],
508	pub params: NoneOr<CalcableValue<'a, Length>>,
509	#[semantic_eq(skip)]
510	pub close: T![')'],
511}
512
513#[cfg(test)]
514mod tests {
515	use super::*;
516	use crate::CssAtomSet;
517	use css_parse::{assert_parse, assert_parse_error, assert_parse_span};
518
519	#[test]
520	fn test_writes() {
521		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "matrix(1,2,3,4,5,6)");
522		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "matrix(1 2 3 4 5 6)");
523		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "matrix(0,0,0,0,0,0)");
524		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "matrix(-1,-2,-3,-4,-5,-6)");
525		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "matrix(1.5,2.5,3.5,4.5,5.5,6.5)");
526
527		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "translate(10px)");
528		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "translate(10px,20px)");
529		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "translate(45%)");
530		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "translate(2rem)");
531		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "translateX(1rem)");
532		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "translateY(1rem)");
533
534		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "scale(1,2)");
535		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "scale(0,0)");
536		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "scale(1)");
537		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "scale(1.5,2.5)");
538		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "scaleX(2)");
539		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "scaleY(2)");
540
541		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "rotate(45deg)");
542		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "rotate(0)");
543		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "rotate(2turn)");
544		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "rotate(20rad)");
545
546		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "skew(1deg,2deg)");
547		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "skew(0,0)");
548		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "skew(1deg)");
549		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "skewX(1deg)");
550		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "skewX(0)");
551		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "skewY(1deg)");
552		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "skewY(0)");
553
554		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "scale3d(10%,10%,10%)");
555		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "rotate3d(1,2,3,10deg)");
556		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,10,20,30,1)");
557	}
558
559	#[test]
560	fn test_substitution() {
561		// Substitution/math functions permitted in <length[-percentage]> slots.
562		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "translate(calc(10px + 5%))");
563		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "translate(var(--x),var(--y))");
564		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "translateX(calc(1rem * 2))");
565		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "translateZ(var(--z))");
566		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "perspective(calc(100px))");
567		// Substitution/math in number/angle/scale slots.
568		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "rotate(calc(45deg))");
569		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "rotate(var(--a))");
570		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "scale(calc(1 + 1),var(--y))");
571		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "skewX(calc(10deg))");
572		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "matrix(calc(1),2,3,4,5,6)");
573		assert_parse!(CssAtomSet::ATOMS, TransformFunction, "rotate3d(1,2,3,var(--a))");
574	}
575
576	#[test]
577	fn test_span() {
578		assert_parse_span!(
579			CssAtomSet::ATOMS,
580			TransformFunction,
581			r#"
582				matrix(1,2,3,4,5,6) translate(0)
583				^^^^^^^^^^^^^^^^^^^
584		"#
585		);
586		assert_parse_span!(
587			CssAtomSet::ATOMS,
588			TransformFunction,
589			r#"
590				translate(0) foo
591				^^^^^^^^^^^^
592		"#
593		);
594		assert_parse_span!(
595			CssAtomSet::ATOMS,
596			TranslateFunction,
597			r#"
598				translate(0) bar
599				^^^^^^^^^^^^
600		"#
601		);
602	}
603
604	#[test]
605	fn test_errors() {
606		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "matrix()");
607		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "matrix(1)");
608		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "matrix(1,2)");
609		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "matrix(one,two,three,four,five,size)");
610
611		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "translate()");
612		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "translate(foo)");
613		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "translateX()");
614		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "translateX(foo)");
615		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "translateY()");
616		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "translateY(foo)");
617
618		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "scale()");
619		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "scale(foo)");
620		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "scaleX()");
621		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "scaleX(foo)");
622		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "scaleY()");
623		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "scaleY(foo)");
624
625		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "rotate()");
626		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "rotate(45px)");
627		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "rotate(all the way around)");
628
629		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "skew()");
630		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "skew(foo)");
631		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "skewX()");
632		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "skewX(foo)");
633		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "skewY()");
634		assert_parse_error!(CssAtomSet::ATOMS, TransformFunction, "skewY(foo)");
635	}
636}