Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update relative color parsing to latest spec #465

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
89 changes: 67 additions & 22 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13534,6 +13534,14 @@ mod tests {
".foo { color: lab(29.2345% 39.3825 20.0664); }",
".foo{color:lab(29.2345% 39.3825 20.0664)}",
);
minify_test(
".foo { color: lab(29.2345 39.3825 20.0664); }",
".foo{color:lab(29.2345% 39.3825 20.0664)}",
);
minify_test(
".foo { color: lab(29.2345% 39.3825% 20.0664%); }",
".foo{color:lab(29.2345% 49.2281 25.083)}",
);
minify_test(
".foo { color: lab(29.2345% 39.3825 20.0664 / 100%); }",
".foo{color:lab(29.2345% 39.3825 20.0664)}",
Expand All @@ -13546,6 +13554,14 @@ mod tests {
".foo { color: lch(29.2345% 44.2 27); }",
".foo{color:lch(29.2345% 44.2 27)}",
);
minify_test(
".foo { color: lch(29.2345 44.2 27); }",
".foo{color:lch(29.2345% 44.2 27)}",
);
minify_test(
".foo { color: lch(29.2345% 44.2% 27deg); }",
".foo{color:lch(29.2345% 66.3 27)}",
);
minify_test(
".foo { color: lch(29.2345% 44.2 45deg); }",
".foo{color:lch(29.2345% 44.2 45)}",
Expand All @@ -13566,10 +13582,26 @@ mod tests {
".foo { color: oklab(40.101% 0.1147 0.0453); }",
".foo{color:oklab(40.101% .1147 .0453)}",
);
minify_test(
".foo { color: oklab(.40101 0.1147 0.0453); }",
".foo{color:oklab(40.101% .1147 .0453)}",
);
minify_test(
".foo { color: oklab(40.101% 0.1147% 0.0453%); }",
".foo{color:oklab(40.101% .0004588 .0001812)}",
);
minify_test(
".foo { color: oklch(40.101% 0.12332 21.555); }",
".foo{color:oklch(40.101% .12332 21.555)}",
);
minify_test(
".foo { color: oklch(.40101 0.12332 21.555); }",
".foo{color:oklch(40.101% .12332 21.555)}",
);
minify_test(
".foo { color: oklch(40.101% 0.12332% 21.555); }",
".foo{color:oklch(40.101% .00049328 21.555)}",
);
minify_test(
".foo { color: oklch(40.101% 0.12332 .5turn); }",
".foo{color:oklch(40.101% .12332 180)}",
Expand Down Expand Up @@ -14280,7 +14312,7 @@ mod tests {
}

test("lab(from indianred calc(l * .8) a b)", "lab(43.1402% 45.7516 23.1557)");
test("lch(from indianred calc(l + 10%) c h)", "lch(63.9252% 51.2776 26.8448)");
test("lch(from indianred calc(l + 10) c h)", "lch(63.9252% 51.2776 26.8448)");
test("lch(from indianred l calc(c - 50) h)", "lch(53.9252% 1.27763 26.8448)");
test(
"lch(from indianred l c calc(h + 180deg))",
Expand All @@ -14296,12 +14328,23 @@ mod tests {
"rgba(205, 92, 92, .7)",
);
test(
"rgb(from rgba(205, 92, 92, .5) r g b / calc(alpha + 20%))",
"rgb(from rgba(205, 92, 92, .5) r g b / calc(alpha + .2))",
"rgba(205, 92, 92, .7)",
);
test("lch(from indianred l sin(c) h)", "lch(53.9252% .84797 26.8448)");
test("lch(from indianred l sqrt(c) h)", "lch(53.9252% 7.16084 26.8448)");
test("lch(from indianred l c sin(h))", "lch(53.9252% 51.2776 .990043)");
test("lch(from indianred l c sin(h))", "lch(53.9252% 51.2776 .451575)");
test("lch(from indianred calc(10% + 20%) c h)", "lch(30% 51.2776 26.8448)");
test("lch(from indianred calc(10 + 20) c h)", "lch(30% 51.2776 26.8448)");
test("lch(from indianred l c calc(10 + 20))", "lch(53.9252% 51.2776 30)");
test(
"lch(from indianred l c calc(10deg + 20deg))",
"lch(53.9252% 51.2776 30)",
);
test(
"lch(from indianred l c calc(10deg + 0.35rad))",
"lch(53.9252% 51.2776 30.0535)",
);

// The following tests were converted from WPT: https://github.com/web-platform-tests/wpt/blob/master/css/css-color/parsing/relative-color-valid.html
// Find: test_valid_value\(`color`, `(.*?)`,\s*`(.*?)`\)
Expand Down Expand Up @@ -14411,21 +14454,15 @@ mod tests {

// Testing permutation.
test("rgb(from rebeccapurple g b r)", "rgb(51, 153, 102)");
test("rgb(from rebeccapurple b alpha r / g)", "rgba(153, 255, 102, 0.2)");
test("rgb(from rebeccapurple r r r / r)", "rgba(102, 102, 102, 0.4)");
test(
"rgb(from rebeccapurple alpha alpha alpha / alpha)",
"rgb(255, 255, 255)",
);
test("rgb(from rebeccapurple b alpha r / g)", "rgba(153, 1, 102, 1)");
test("rgb(from rebeccapurple r r r / r)", "rgba(102, 102, 102, 1)");
test("rgb(from rebeccapurple alpha alpha alpha / alpha)", "rgb(1, 1, 1)");
test("rgb(from rgb(20%, 40%, 60%, 80%) g b r)", "rgb(102, 153, 51)");
test(
"rgb(from rgb(20%, 40%, 60%, 80%) b alpha r / g)",
"rgba(153, 204, 51, 0.4)",
);
test("rgb(from rgb(20%, 40%, 60%, 80%) r r r / r)", "rgba(51, 51, 51, 0.2)");
test("rgb(from rgb(20%, 40%, 60%, 80%) b alpha r / g)", "rgba(153, 1, 51, 1)");
test("rgb(from rgb(20%, 40%, 60%, 80%) r r r / r)", "rgba(51, 51, 51, 1)");
test(
"rgb(from rgb(20%, 40%, 60%, 80%) alpha alpha alpha / alpha)",
"rgba(204, 204, 204, 0.8)",
"rgba(1, 1, 1, 0.8)",
);

// Testing mixes of number and percentage. (These would not be allowed in the non-relative syntax).
Expand Down Expand Up @@ -15150,23 +15187,31 @@ mod tests {
// NOTE: 'c' is a vaild hue, as hue is <angle>|<number>.
test(
&format!("{}(from {}(70% 45 30) alpha c h / l)", color_space, color_space),
&format!("{}(100% 45 30 / 0.7)", color_space),
&format!(
"{}(1 45 30 / {})",
color_space,
if *color_space == "lch" { "1" } else { ".7" }
),
);
test(
&format!("{}(from {}(70% 45 30) l c c / alpha)", color_space, color_space),
&format!("{}(70% 45 45)", color_space),
);
test(
&format!("{}(from {}(70% 45 30) alpha c h / alpha)", color_space, color_space),
&format!("{}(100% 45 30)", color_space),
&format!("{}(1 45 30)", color_space),
);
test(
&format!("{}(from {}(70% 45 30) alpha c c / alpha)", color_space, color_space),
&format!("{}(100% 45 45)", color_space),
&format!("{}(1 45 45)", color_space),
);
test(
&format!("{}(from {}(70% 45 30 / 40%) alpha c h / l)", color_space, color_space),
&format!("{}(40% 45 30 / 0.7)", color_space),
&format!(
"{}(.4 45 30 / {})",
color_space,
if *color_space == "lch" { "1" } else { ".7" }
),
);
test(
&format!("{}(from {}(70% 45 30 / 40%) l c c / alpha)", color_space, color_space),
Expand All @@ -15177,14 +15222,14 @@ mod tests {
"{}(from {}(70% 45 30 / 40%) alpha c h / alpha)",
color_space, color_space
),
&format!("{}(40% 45 30 / 0.4)", color_space),
&format!("{}(.4 45 30 / 0.4)", color_space),
);
test(
&format!(
"{}(from {}(70% 45 30 / 40%) alpha c c / alpha)",
color_space, color_space
),
&format!("{}(40% 45 45 / 0.4)", color_space),
&format!("{}(.4 45 45 / 0.4)", color_space),
);

// Testing with calc().
Expand Down Expand Up @@ -16052,7 +16097,7 @@ mod tests {
);
minify_test(
".foo{color:hsl(from rebeccapurple alpha alpha alpha / alpha)}",
".foo{color:hsl(from rebeccapurple alpha alpha alpha/alpha)}",
".foo{color:#fff}",
);
}
}
Expand Down
17 changes: 6 additions & 11 deletions src/properties/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1479,21 +1479,16 @@ impl<'i> UnresolvedColor<'i> {
where
W: std::fmt::Write,
{
#[inline]
fn c(c: &f32) -> i32 {
(c * 255.0).round().clamp(0.0, 255.0) as i32
}

match self {
UnresolvedColor::RGB { r, g, b, alpha } => {
if let Some(targets) = dest.targets {
if !compat::Feature::SpaceSeparatedColorFunction.is_compatible(targets) {
dest.write_str("rgba(")?;
c(r).to_css(dest)?;
r.to_css(dest)?;
dest.delim(',', false)?;
c(g).to_css(dest)?;
g.to_css(dest)?;
dest.delim(',', false)?;
c(b).to_css(dest)?;
b.to_css(dest)?;
dest.delim(',', false)?;
alpha.to_css(dest, is_custom_property)?;
dest.write_char(')')?;
Expand All @@ -1502,11 +1497,11 @@ impl<'i> UnresolvedColor<'i> {
}

dest.write_str("rgb(")?;
c(r).to_css(dest)?;
r.to_css(dest)?;
dest.write_char(' ')?;
c(g).to_css(dest)?;
g.to_css(dest)?;
dest.write_char(' ')?;
c(b).to_css(dest)?;
b.to_css(dest)?;
dest.delim('/', true)?;
alpha.to_css(dest, is_custom_property)?;
dest.write_char(')')
Expand Down
17 changes: 13 additions & 4 deletions src/values/angle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,13 @@ impl Into<Calc<Angle>> for Angle {
}
}

impl From<Calc<Angle>> for Angle {
fn from(calc: Calc<Angle>) -> Angle {
impl TryFrom<Calc<Angle>> for Angle {
type Error = ();

fn try_from(calc: Calc<Angle>) -> Result<Angle, ()> {
match calc {
Calc::Value(v) => *v,
_ => unreachable!(),
Calc::Value(v) => Ok(*v),
_ => Err(()),
}
}
}
Expand Down Expand Up @@ -284,6 +286,13 @@ macro_rules! impl_try_from_angle {
Err(())
}
}

impl TryInto<crate::values::angle::Angle> for $t {
type Error = ();
fn try_into(self) -> Result<crate::values::angle::Angle, Self::Error> {
Err(())
}
}
};
}

Expand Down
35 changes: 19 additions & 16 deletions src/values/calc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,9 @@ impl<
+ TrySign
+ std::cmp::PartialOrd<V>
+ Into<Calc<V>>
+ From<Calc<V>>
+ TryFrom<Calc<V>>
+ TryFrom<Angle>
+ TryInto<Angle>
+ Clone
+ std::fmt::Debug,
> Parse<'i> for Calc<V>
Expand All @@ -288,8 +289,9 @@ impl<
+ TrySign
+ std::cmp::PartialOrd<V>
+ Into<Calc<V>>
+ From<Calc<V>>
+ TryFrom<Calc<V>>
+ TryFrom<Angle>
+ TryInto<Angle>
+ Clone
+ std::fmt::Debug,
> Calc<V>
Expand Down Expand Up @@ -501,12 +503,12 @@ impl<
match *input.next()? {
Token::Delim('+') => {
let next = Calc::parse_product(input, parse_ident)?;
cur = cur.add(next);
cur = cur.add(next).map_err(|_| input.new_custom_error(ParserError::InvalidValue))?;
}
Token::Delim('-') => {
let mut rhs = Calc::parse_product(input, parse_ident)?;
rhs = rhs * -1.0;
cur = cur.add(rhs);
cur = cur.add(rhs).map_err(|_| input.new_custom_error(ParserError::InvalidValue))?;
}
ref t => {
let t = t.clone();
Expand Down Expand Up @@ -695,9 +697,12 @@ impl<
) -> Result<Self, ParseError<'i, ParserError<'i>>> {
input.parse_nested_block(|input| {
let v: Calc<Angle> = Calc::parse_sum(input, |v| {
parse_ident(v).and_then(|v| match v {
Calc::Number(v) => Some(Calc::Number(v)),
_ => None,
parse_ident(v).and_then(|v| -> Option<Calc<Angle>> {
match v {
Calc::Number(v) => Some(Calc::Number(v)),
Calc::Value(v) => (*v).try_into().ok().map(|v| Calc::Value(Box::new(v))),
_ => None,
}
})
})?;
let rad = match v {
Expand Down Expand Up @@ -854,19 +859,17 @@ impl<V: std::ops::Mul<f32, Output = V>> std::ops::Mul<f32> for Calc<V> {
}
}

impl<V: AddInternal + std::convert::Into<Calc<V>> + std::convert::From<Calc<V>> + std::fmt::Debug> AddInternal
for Calc<V>
{
fn add(self, other: Calc<V>) -> Calc<V> {
match (self, other) {
impl<V: AddInternal + std::convert::Into<Calc<V>> + std::convert::TryFrom<Calc<V>> + std::fmt::Debug> Calc<V> {
pub(crate) fn add(self, other: Calc<V>) -> Result<Calc<V>, <V as TryFrom<Calc<V>>>::Error> {
Ok(match (self, other) {
(Calc::Value(a), Calc::Value(b)) => (a.add(*b)).into(),
(Calc::Number(a), Calc::Number(b)) => Calc::Number(a + b),
(Calc::Value(a), b) => (a.add(V::from(b))).into(),
(a, Calc::Value(b)) => (V::from(a).add(*b)).into(),
(Calc::Value(a), b) => (a.add(V::try_from(b)?)).into(),
(a, Calc::Value(b)) => (V::try_from(a)?.add(*b)).into(),
(Calc::Function(a), b) => Calc::Sum(Box::new(Calc::Function(a)), Box::new(b)),
(a, Calc::Function(b)) => Calc::Sum(Box::new(a), Box::new(Calc::Function(b))),
(a, b) => V::from(a).add(V::from(b)).into(),
}
(a, b) => V::try_from(a)?.add(V::try_from(b)?).into(),
})
}
}

Expand Down