1use super::{RotateStyleValue, TransformOriginStyleValue};
2use crate::{Angle, CalcableValue, CssAtomSet, KeywordValue, Length, Number, NumericValue, PositionOne, PositionTwo};
3use css_parse::{Cursor, Diagnostic, Parse, Parser, Peek, Result as ParseResult, T};
4
5impl<'a> Parse<'a> for TransformOriginStyleValue<'a> {
6 fn parse<I>(p: &mut Parser<'a, I>) -> ParseResult<Self>
7 where
8 I: Iterator<Item = Cursor> + Clone,
9 {
10 let first = p.parse::<PositionOne>()?;
11 if !p.peek::<PositionOne>() {
12 return Ok(Self::PositionOne(crate::Value::Literal(first)));
13 }
14 let second_c = p.peek_n(1);
15 let second = p.parse::<PositionOne>()?;
16 let two = PositionTwo::from_two(p, first, second, second_c)?;
17 Ok(Self::PositionTwo(crate::Value::Literal(two), p.parse_if_peek::<CalcableValue<Length>>()?))
18 }
19}
20
21type Vector<'a> = (NumericValue<'a, Number>, NumericValue<'a, Number>, NumericValue<'a, Number>);
22
23impl<'a> Parse<'a> for RotateStyleValue<'a> {
24 fn parse<I>(p: &mut Parser<'a, I>) -> ParseResult<Self>
25 where
26 I: Iterator<Item = Cursor> + Clone,
27 {
28 let c = p.peek_n(1);
29 if <T![Ident]>::peek(p, c) {
30 if p.equals_atom(c, &CssAtomSet::None) {
31 return p.parse::<KeywordValue<'a, T![Ident]>>().map(Self::None);
32 }
33 let variant = match p.to_atom::<CssAtomSet>(c) {
34 CssAtomSet::X => RotateStyleValue::XAngle,
35 CssAtomSet::Y => RotateStyleValue::YAngle,
36 CssAtomSet::Z => RotateStyleValue::ZAngle,
37 _ => Err(Diagnostic::new(c, Diagnostic::unexpected))?,
38 };
39 let keyword = p.parse::<KeywordValue<'a, T![Ident]>>()?;
40 return Ok(variant(keyword, p.parse::<CalcableValue<'a, Angle>>()?));
41 }
42 if <T![Number]>::peek(p, c) {
43 let vector = p.parse::<Vector<'a>>()?;
44 return Ok(Self::NumberAngle(vector, p.parse::<CalcableValue<'a, Angle>>()?));
45 }
46 let angle = p.parse::<CalcableValue<'a, Angle>>()?;
47 let c = p.peek_n(1);
48 if <T![Ident]>::peek(p, c) {
49 let variant = match p.to_atom::<CssAtomSet>(c) {
50 CssAtomSet::X => RotateStyleValue::XAngle,
51 CssAtomSet::Y => RotateStyleValue::YAngle,
52 CssAtomSet::Z => RotateStyleValue::ZAngle,
53 _ => return Ok(Self::Angle(angle)),
54 };
55 let keyword = p.parse::<KeywordValue<'a, T![Ident]>>()?;
56 return Ok(variant(keyword, angle));
57 } else if <T![Number]>::peek(p, c) {
58 return Ok(Self::NumberAngle(p.parse::<Vector<'a>>()?, angle));
59 }
60 Ok(Self::Angle(angle))
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::super::*;
67 use crate::CssAtomSet;
68 use css_parse::{assert_parse, assert_parse_error, assert_peek_false};
69
70 #[test]
71 fn test_writes() {
72 assert_parse!(CssAtomSet::ATOMS, TransformStyleValue, "none");
73 assert_parse!(CssAtomSet::ATOMS, TransformStyleValue, "scale(1)");
74 assert_parse!(CssAtomSet::ATOMS, TransformBoxStyleValue, "fill-box");
75 assert_parse!(CssAtomSet::ATOMS, ScaleStyleValue, "none");
76 assert_parse!(CssAtomSet::ATOMS, ScaleStyleValue, "1%");
77 assert_parse!(CssAtomSet::ATOMS, ScaleStyleValue, "1 2 3");
78 assert_parse!(CssAtomSet::ATOMS, ScaleStyleValue, "1.7 50%");
79 assert_parse!(CssAtomSet::ATOMS, TransformStyleStyleValue, "flat");
80 assert_parse!(CssAtomSet::ATOMS, PerspectiveOriginStyleValue, "1px");
81 assert_parse!(CssAtomSet::ATOMS, BackfaceVisibilityStyleValue, "visible");
82 }
83
84 #[test]
85 fn test_errors() {
86 assert_peek_false!(CssAtomSet::ATOMS, TransformStyleValue, "auto");
87 assert_parse_error!(CssAtomSet::ATOMS, ScaleStyleValue, "none none");
88 }
89
90 #[test]
91 fn test_rotate() {
92 assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "none");
93 assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "45deg");
94 assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "x 45deg");
95 assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "y 45deg");
96 assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "z 45deg");
97 assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "45deg x");
98 assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "1 2 3 45deg");
99 assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "45deg 1 2 3");
100 assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "z calc(45deg * 2)");
101 assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "x var(--angle)");
102 assert_parse!(CssAtomSet::ATOMS, RotateStyleValue, "var(--angle) y");
103 }
104
105 #[test]
106 fn test_rotate_errors() {
107 assert_parse_error!(CssAtomSet::ATOMS, RotateStyleValue, "x");
108 assert_parse_error!(CssAtomSet::ATOMS, RotateStyleValue, "1 2 45deg");
109 assert_parse_error!(CssAtomSet::ATOMS, RotateStyleValue, "none 45deg");
110 }
111
112 #[test]
113 fn test_transform_origin() {
114 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "left");
115 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "center");
116 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "right");
117 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "top");
118 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "bottom");
119 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "50%");
120 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "10px");
121 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "0");
122 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "left top");
123 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "left center");
124 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "left bottom");
125 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "center top");
126 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "center center");
127 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "center bottom");
128 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "right top");
129 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "right center");
130 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "right bottom");
131 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "50% 50%");
132 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "10px 20px");
133 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "0 0");
134 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "left 50%");
135 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "right 25%");
136 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "center 10px");
137 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "50% top");
138 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "75% bottom");
139 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "10px center");
140 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "left top 5px");
141 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "center center 0px");
142 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "50% 50% 10px");
143 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "right bottom 100px");
144 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "10px 20px 30px");
145 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "top left");
146 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "top center");
147 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "top right");
148 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "bottom left");
149 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "bottom center");
150 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "bottom right");
151 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "top left 5px");
152 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "bottom right 20px");
153 assert_parse!(CssAtomSet::ATOMS, TransformOriginStyleValue, "top center 0px");
154 }
155
156 #[test]
157 fn test_transform_origin_errors() {
158 assert_peek_false!(CssAtomSet::ATOMS, TransformOriginStyleValue, "auto");
159 assert_parse_error!(CssAtomSet::ATOMS, TransformOriginStyleValue, "top top");
160 assert_parse_error!(CssAtomSet::ATOMS, TransformOriginStyleValue, "left left");
161 assert_parse_error!(CssAtomSet::ATOMS, TransformOriginStyleValue, "left top 50%");
162 assert_parse_error!(CssAtomSet::ATOMS, TransformOriginStyleValue, "left top 0px extra");
163 }
164}