Skip to content

Commit cbd392f

Browse files
committed
Support parsing angles with unitless zero exceptions
Fixes #298
1 parent 6e47cdb commit cbd392f

File tree

5 files changed

+71
-24
lines changed

5 files changed

+71
-24
lines changed

src/lib.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8710,6 +8710,8 @@ mod tests {
87108710
minify_test(".foo { transform: rotateX(405deg)}", ".foo{transform:rotateX(405deg)}");
87118711
minify_test(".foo { transform: rotateY(405deg)}", ".foo{transform:rotateY(405deg)}");
87128712
minify_test(".foo { transform: rotate(-200deg)}", ".foo{transform:rotate(-200deg)}");
8713+
minify_test(".foo { transform: rotate(0)", ".foo{transform:rotate(0)}");
8714+
minify_test(".foo { transform: rotate(0deg)", ".foo{transform:rotate(0)}");
87138715
minify_test(
87148716
".foo { transform: rotateX(-200deg)}",
87158717
".foo{transform:rotateX(-200deg)}",
@@ -8969,6 +8971,10 @@ mod tests {
89698971
".foo { background: linear-gradient(yellow, red 30%, red 40%, blue); }",
89708972
".foo{background:linear-gradient(#ff0,red 30% 40%,#00f)}",
89718973
);
8974+
minify_test(
8975+
".foo { background: linear-gradient(0, yellow, blue); }",
8976+
".foo{background:linear-gradient(#00f,#ff0)}",
8977+
);
89728978
minify_test(
89738979
".foo { background: -webkit-linear-gradient(yellow, blue) }",
89748980
".foo{background:-webkit-linear-gradient(#ff0,#00f)}",
@@ -9141,6 +9147,10 @@ mod tests {
91419147
".foo { background: conic-gradient(from 0deg, #f06, gold) }",
91429148
".foo{background:conic-gradient(#f06,gold)}",
91439149
);
9150+
minify_test(
9151+
".foo { background: conic-gradient(from 0, #f06, gold) }",
9152+
".foo{background:conic-gradient(#f06,gold)}",
9153+
);
91449154
minify_test(
91459155
".foo { background: conic-gradient(from 0deg at center, #f06, gold) }",
91469156
".foo{background:conic-gradient(#f06,gold)}",
@@ -20620,6 +20630,7 @@ mod tests {
2062020630
".foo { filter: contrast(175%) brightness(3%); }",
2062120631
".foo{filter:contrast(175%)brightness(3%)}",
2062220632
);
20633+
minify_test(".foo { filter: hue-rotate(0) }", ".foo{filter:hue-rotate()}");
2062320634

2062420635
prefix_test(
2062520636
".foo { filter: blur(5px) }",

src/properties/effects.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ impl<'i> Parse<'i> for Filter<'i> {
7373
},
7474
"hue-rotate" => {
7575
input.parse_nested_block(|input| {
76-
Ok(Filter::HueRotate(input.try_parse(Angle::parse).unwrap_or(Angle::Deg(0.0))))
76+
// Spec has an exception for unitless zero angles: https://github.com/w3c/fxtf-drafts/issues/228
77+
Ok(Filter::HueRotate(input.try_parse(Angle::parse_with_unitless_zero).unwrap_or(Angle::zero())))
7778
})
7879
},
7980
"invert" => {

src/properties/transform.rs

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -948,19 +948,19 @@ impl<'i> Parse<'i> for Transform {
948948
Ok(Transform::Scale3d(x, y, z))
949949
},
950950
"rotate" => {
951-
let angle = Angle::parse(input)?;
951+
let angle = Angle::parse_with_unitless_zero(input)?;
952952
Ok(Transform::Rotate(angle))
953953
},
954954
"rotatex" => {
955-
let angle = Angle::parse(input)?;
955+
let angle = Angle::parse_with_unitless_zero(input)?;
956956
Ok(Transform::RotateX(angle))
957957
},
958958
"rotatey" => {
959-
let angle = Angle::parse(input)?;
959+
let angle = Angle::parse_with_unitless_zero(input)?;
960960
Ok(Transform::RotateY(angle))
961961
},
962962
"rotatez" => {
963-
let angle = Angle::parse(input)?;
963+
let angle = Angle::parse_with_unitless_zero(input)?;
964964
Ok(Transform::RotateZ(angle))
965965
},
966966
"rotate3d" => {
@@ -970,24 +970,24 @@ impl<'i> Parse<'i> for Transform {
970970
input.expect_comma()?;
971971
let z = f32::parse(input)?;
972972
input.expect_comma()?;
973-
let angle = Angle::parse(input)?;
973+
let angle = Angle::parse_with_unitless_zero(input)?;
974974
Ok(Transform::Rotate3d(x, y, z, angle))
975975
},
976976
"skew" => {
977-
let x = Angle::parse(input)?;
977+
let x = Angle::parse_with_unitless_zero(input)?;
978978
if input.try_parse(|input| input.expect_comma()).is_ok() {
979-
let y = Angle::parse(input)?;
979+
let y = Angle::parse_with_unitless_zero(input)?;
980980
Ok(Transform::Skew(x, y))
981981
} else {
982982
Ok(Transform::Skew(x, Angle::Deg(0.0)))
983983
}
984984
},
985985
"skewx" => {
986-
let angle = Angle::parse(input)?;
986+
let angle = Angle::parse_with_unitless_zero(input)?;
987987
Ok(Transform::SkewX(angle))
988988
},
989989
"skewy" => {
990-
let angle = Angle::parse(input)?;
990+
let angle = Angle::parse_with_unitless_zero(input)?;
991991
Ok(Transform::SkewY(angle))
992992
},
993993
"perspective" => {
@@ -1135,37 +1135,37 @@ impl ToCss for Transform {
11351135
}
11361136
Rotate(angle) => {
11371137
dest.write_str("rotate(")?;
1138-
angle.to_css(dest)?;
1138+
angle.to_css_with_unitless_zero(dest)?;
11391139
dest.write_char(')')
11401140
}
11411141
RotateX(angle) => {
11421142
dest.write_str("rotateX(")?;
1143-
angle.to_css(dest)?;
1143+
angle.to_css_with_unitless_zero(dest)?;
11441144
dest.write_char(')')
11451145
}
11461146
RotateY(angle) => {
11471147
dest.write_str("rotateY(")?;
1148-
angle.to_css(dest)?;
1148+
angle.to_css_with_unitless_zero(dest)?;
11491149
dest.write_char(')')
11501150
}
11511151
RotateZ(angle) => {
11521152
dest.write_str(if dest.minify { "rotate(" } else { "rotateZ(" })?;
1153-
angle.to_css(dest)?;
1153+
angle.to_css_with_unitless_zero(dest)?;
11541154
dest.write_char(')')
11551155
}
11561156
Rotate3d(x, y, z, angle) => {
11571157
if dest.minify && *x == 1.0 && *y == 0.0 && *z == 0.0 {
11581158
// rotate3d(1, 0, 0, a) => rotateX(a)
11591159
dest.write_str("rotateX(")?;
1160-
angle.to_css(dest)?;
1160+
angle.to_css_with_unitless_zero(dest)?;
11611161
} else if dest.minify && *x == 0.0 && *y == 1.0 && *z == 0.0 {
11621162
// rotate3d(0, 1, 0, a) => rotateY(a)
11631163
dest.write_str("rotateY(")?;
1164-
angle.to_css(dest)?;
1164+
angle.to_css_with_unitless_zero(dest)?;
11651165
} else if dest.minify && *x == 0.0 && *y == 0.0 && *z == 1.0 {
11661166
// rotate3d(0, 0, 1, a) => rotate(a)
11671167
dest.write_str("rotate(")?;
1168-
angle.to_css(dest)?;
1168+
angle.to_css_with_unitless_zero(dest)?;
11691169
} else {
11701170
dest.write_str("rotate3d(")?;
11711171
x.to_css(dest)?;
@@ -1174,32 +1174,32 @@ impl ToCss for Transform {
11741174
dest.delim(',', false)?;
11751175
z.to_css(dest)?;
11761176
dest.delim(',', false)?;
1177-
angle.to_css(dest)?;
1177+
angle.to_css_with_unitless_zero(dest)?;
11781178
}
11791179
dest.write_char(')')
11801180
}
11811181
Skew(x, y) => {
11821182
if dest.minify && x.is_zero() && !y.is_zero() {
11831183
dest.write_str("skewY(")?;
1184-
y.to_css(dest)?
1184+
y.to_css_with_unitless_zero(dest)?
11851185
} else {
11861186
dest.write_str("skew(")?;
11871187
x.to_css(dest)?;
11881188
if !y.is_zero() {
11891189
dest.delim(',', false)?;
1190-
y.to_css(dest)?;
1190+
y.to_css_with_unitless_zero(dest)?;
11911191
}
11921192
}
11931193
dest.write_char(')')
11941194
}
11951195
SkewX(angle) => {
11961196
dest.write_str(if dest.minify { "skew(" } else { "skewX(" })?;
1197-
angle.to_css(dest)?;
1197+
angle.to_css_with_unitless_zero(dest)?;
11981198
dest.write_char(')')
11991199
}
12001200
SkewY(angle) => {
12011201
dest.write_str("skewY(")?;
1202-
angle.to_css(dest)?;
1202+
angle.to_css_with_unitless_zero(dest)?;
12031203
dest.write_char(')')
12041204
}
12051205
Perspective(len) => {

src/values/angle.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,22 @@ pub enum Angle {
3737

3838
impl<'i> Parse<'i> for Angle {
3939
fn parse<'t>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
40+
Self::parse_internal(input, false)
41+
}
42+
}
43+
44+
impl Angle {
45+
/// Parses an angle, allowing unitless zero values.
46+
pub fn parse_with_unitless_zero<'i, 't>(
47+
input: &mut Parser<'i, 't>,
48+
) -> Result<Self, ParseError<'i, ParserError<'i>>> {
49+
Self::parse_internal(input, true)
50+
}
51+
52+
fn parse_internal<'i, 't>(
53+
input: &mut Parser<'i, 't>,
54+
allow_unitless_zero: bool,
55+
) -> Result<Self, ParseError<'i, ParserError<'i>>> {
4056
match input.try_parse(Calc::parse) {
4157
Ok(Calc::Value(v)) => return Ok(*v),
4258
// Angles are always compatible, so they will always compute to a value.
@@ -56,6 +72,7 @@ impl<'i> Parse<'i> for Angle {
5672
_ => return Err(location.new_unexpected_token_error(token.clone())),
5773
}
5874
}
75+
Token::Number { value, .. } if value == 0.0 && allow_unitless_zero => Ok(Angle::zero()),
5976
ref token => return Err(location.new_unexpected_token_error(token.clone())),
6077
}
6178
}
@@ -86,6 +103,20 @@ impl ToCss for Angle {
86103
}
87104
}
88105

106+
impl Angle {
107+
/// Prints the angle, allowing unitless zero values.
108+
pub fn to_css_with_unitless_zero<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
109+
where
110+
W: std::fmt::Write,
111+
{
112+
if self.is_zero() {
113+
(0.0).to_css(dest)
114+
} else {
115+
self.to_css(dest)
116+
}
117+
}
118+
}
119+
89120
impl Angle {
90121
/// Returns the angle in radians.
91122
pub fn to_radians(&self) -> CSSNumber {

src/values/gradient.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,9 @@ impl LineDirection {
388388
input: &mut Parser<'i, 't>,
389389
is_prefixed: bool,
390390
) -> Result<Self, ParseError<'i, ParserError<'i>>> {
391-
if let Ok(angle) = input.try_parse(Angle::parse) {
391+
// Spec allows unitless zero angles for gradients.
392+
// https://w3c.github.io/csswg-drafts/css-images-3/#linear-gradient-syntax
393+
if let Ok(angle) = input.try_parse(Angle::parse_with_unitless_zero) {
392394
return Ok(LineDirection::Angle(angle));
393395
}
394396

@@ -672,7 +674,9 @@ impl ConicGradient {
672674
fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
673675
let angle = input.try_parse(|input| {
674676
input.expect_ident_matching("from")?;
675-
Angle::parse(input)
677+
// Spec allows unitless zero angles for gradients.
678+
// https://w3c.github.io/csswg-drafts/css-images-4/#valdef-conic-gradient-angle
679+
Angle::parse_with_unitless_zero(input)
676680
});
677681

678682
let position = input.try_parse(|input| {

0 commit comments

Comments
 (0)