2020-03-03 19:51:02 -05:00
|
|
|
use std::collections::HashMap;
|
2020-02-14 12:43:12 -05:00
|
|
|
|
2020-03-22 22:28:54 -04:00
|
|
|
use num_traits::One;
|
|
|
|
|
2020-02-14 12:43:12 -05:00
|
|
|
use super::Builtin;
|
|
|
|
use crate::color::Color;
|
2020-02-16 16:11:24 -05:00
|
|
|
use crate::common::QuoteKind;
|
2020-03-19 16:24:31 -04:00
|
|
|
use crate::unit::Unit;
|
2020-02-14 12:43:12 -05:00
|
|
|
use crate::value::{Number, Value};
|
|
|
|
|
2020-03-03 19:51:02 -05:00
|
|
|
pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
2020-03-16 10:35:38 -04:00
|
|
|
f.insert(
|
|
|
|
"hsl".to_owned(),
|
2020-04-04 18:17:04 -04:00
|
|
|
Builtin::new(|mut args, scope, super_selector| {
|
2020-03-22 23:41:02 -04:00
|
|
|
if args.is_empty() {
|
2020-04-12 19:37:12 -04:00
|
|
|
return Err(("Missing argument $channels.", args.span()).into());
|
2020-03-22 23:41:02 -04:00
|
|
|
}
|
|
|
|
|
2020-03-19 23:44:53 -04:00
|
|
|
if args.len() == 1 {
|
2020-04-04 18:17:04 -04:00
|
|
|
let mut channels = match arg!(args, scope, super_selector, 0, "channels") {
|
2020-03-23 19:56:24 -04:00
|
|
|
Value::List(v, ..) => v,
|
2020-04-12 19:37:12 -04:00
|
|
|
_ => return Err(("Missing argument $channels.", args.span()).into()),
|
2020-03-19 23:44:53 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
if channels.len() > 3 {
|
2020-04-12 19:37:12 -04:00
|
|
|
return Err((
|
|
|
|
format!(
|
|
|
|
"Only 3 elements allowed, but {} were passed.",
|
|
|
|
channels.len()
|
|
|
|
),
|
|
|
|
args.span(),
|
2020-03-19 23:44:53 -04:00
|
|
|
)
|
2020-04-12 19:37:12 -04:00
|
|
|
.into());
|
2020-03-16 10:35:38 -04:00
|
|
|
}
|
2020-03-19 23:44:53 -04:00
|
|
|
|
2020-03-23 12:52:23 -04:00
|
|
|
let lightness = match channels.pop() {
|
2020-03-19 23:44:53 -04:00
|
|
|
Some(Value::Dimension(n, _)) => n / Number::from(100),
|
2020-04-12 19:37:12 -04:00
|
|
|
Some(v) => {
|
|
|
|
return Err((
|
|
|
|
format!(
|
|
|
|
"$lightness: {} is not a number.",
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
|
|
|
None => return Err(("Missing element $lightness.", args.span()).into()),
|
2020-03-19 23:44:53 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
let saturation = match channels.pop() {
|
|
|
|
Some(Value::Dimension(n, _)) => n / Number::from(100),
|
2020-04-12 19:37:12 -04:00
|
|
|
Some(v) => {
|
|
|
|
return Err((
|
|
|
|
format!(
|
|
|
|
"$saturation: {} is not a number.",
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
|
|
|
None => return Err(("Missing element $saturation.", args.span()).into()),
|
2020-03-19 23:44:53 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
let hue = match channels.pop() {
|
|
|
|
Some(Value::Dimension(n, _)) => n,
|
2020-04-12 19:37:12 -04:00
|
|
|
Some(v) => {
|
|
|
|
return Err((
|
|
|
|
format!("$hue: {} is not a number.", v.to_css_string(args.span())?),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
|
|
|
None => return Err(("Missing element $hue.", args.span()).into()),
|
2020-03-19 23:44:53 -04:00
|
|
|
};
|
|
|
|
|
2020-04-21 18:54:19 -04:00
|
|
|
Ok(Value::Color(Box::new(Color::from_hsla(
|
2020-03-19 23:44:53 -04:00
|
|
|
hue,
|
|
|
|
saturation,
|
2020-03-23 12:52:23 -04:00
|
|
|
lightness,
|
2020-03-22 22:28:54 -04:00
|
|
|
Number::one(),
|
2020-04-21 18:54:19 -04:00
|
|
|
))))
|
2020-03-19 23:44:53 -04:00
|
|
|
} else {
|
2020-04-04 18:17:04 -04:00
|
|
|
let hue = match arg!(args, scope, super_selector, 0, "hue") {
|
2020-03-19 23:44:53 -04:00
|
|
|
Value::Dimension(n, _) => n,
|
2020-04-06 23:38:17 -04:00
|
|
|
v if v.is_special_function() => {
|
|
|
|
let saturation = arg!(args, scope, super_selector, 1, "saturation");
|
|
|
|
let lightness = arg!(args, scope, super_selector, 2, "lightness");
|
2020-04-12 19:37:12 -04:00
|
|
|
let mut string = format!(
|
|
|
|
"hsl({}, {}, {}",
|
|
|
|
v.to_css_string(args.span())?,
|
|
|
|
saturation.to_css_string(args.span())?,
|
|
|
|
lightness.to_css_string(args.span())?
|
|
|
|
);
|
2020-04-06 23:38:17 -04:00
|
|
|
if !args.is_empty() {
|
|
|
|
string.push_str(", ");
|
|
|
|
string.push_str(
|
2020-04-12 19:37:12 -04:00
|
|
|
&arg!(args, scope, super_selector, 3, "alpha")
|
|
|
|
.to_css_string(args.span())?,
|
2020-04-06 23:38:17 -04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
string.push(')');
|
|
|
|
return Ok(Value::Ident(string, QuoteKind::None));
|
|
|
|
}
|
2020-04-12 19:37:12 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!("$hue: {} is not a number.", v.to_css_string(args.span())?),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-19 23:44:53 -04:00
|
|
|
};
|
2020-04-04 18:17:04 -04:00
|
|
|
let saturation = match arg!(args, scope, super_selector, 1, "saturation") {
|
2020-03-19 23:44:53 -04:00
|
|
|
Value::Dimension(n, _) => n / Number::from(100),
|
2020-04-06 23:38:17 -04:00
|
|
|
v if v.is_special_function() => {
|
|
|
|
let lightness = arg!(args, scope, super_selector, 2, "lightness");
|
2020-04-12 19:37:12 -04:00
|
|
|
let mut string = format!(
|
|
|
|
"hsl({}, {}, {}",
|
|
|
|
hue,
|
|
|
|
v.to_css_string(args.span())?,
|
|
|
|
lightness.to_css_string(args.span())?
|
|
|
|
);
|
2020-04-06 23:38:17 -04:00
|
|
|
if !args.is_empty() {
|
|
|
|
string.push_str(", ");
|
|
|
|
string.push_str(
|
2020-04-12 19:37:12 -04:00
|
|
|
&arg!(args, scope, super_selector, 3, "alpha")
|
|
|
|
.to_css_string(args.span())?,
|
2020-04-06 23:38:17 -04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
string.push(')');
|
|
|
|
return Ok(Value::Ident(string, QuoteKind::None));
|
|
|
|
}
|
2020-04-12 19:37:12 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!(
|
|
|
|
"$saturation: {} is not a number.",
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-19 23:44:53 -04:00
|
|
|
};
|
2020-04-04 18:17:04 -04:00
|
|
|
let lightness = match arg!(args, scope, super_selector, 2, "lightness") {
|
2020-03-19 23:44:53 -04:00
|
|
|
Value::Dimension(n, _) => n / Number::from(100),
|
2020-04-06 23:38:17 -04:00
|
|
|
v if v.is_special_function() => {
|
2020-04-12 19:37:12 -04:00
|
|
|
let mut string = format!(
|
|
|
|
"hsl({}, {}, {}",
|
|
|
|
hue,
|
|
|
|
saturation,
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
);
|
2020-04-06 23:38:17 -04:00
|
|
|
if !args.is_empty() {
|
|
|
|
string.push_str(", ");
|
|
|
|
string.push_str(
|
2020-04-12 19:37:12 -04:00
|
|
|
&arg!(args, scope, super_selector, 3, "alpha")
|
|
|
|
.to_css_string(args.span())?,
|
2020-04-06 23:38:17 -04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
string.push(')');
|
|
|
|
return Ok(Value::Ident(string, QuoteKind::None));
|
|
|
|
}
|
2020-04-12 19:37:12 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!(
|
|
|
|
"$lightness: {} is not a number.",
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-19 23:44:53 -04:00
|
|
|
};
|
|
|
|
let alpha = match arg!(
|
|
|
|
args,
|
2020-04-04 18:17:04 -04:00
|
|
|
scope,
|
|
|
|
super_selector,
|
2020-03-19 23:44:53 -04:00
|
|
|
3,
|
2020-03-22 22:28:54 -04:00
|
|
|
"alpha" = Value::Dimension(Number::one(), Unit::None)
|
2020-03-19 23:44:53 -04:00
|
|
|
) {
|
|
|
|
Value::Dimension(n, Unit::None) => n,
|
|
|
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
|
|
|
v @ Value::Dimension(..) => {
|
2020-04-12 19:37:12 -04:00
|
|
|
return Err((
|
|
|
|
format!(
|
|
|
|
"$alpha: Expected {} to have no units or \"%\".",
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
),
|
|
|
|
args.span(),
|
2020-03-19 23:44:53 -04:00
|
|
|
)
|
2020-04-12 19:37:12 -04:00
|
|
|
.into())
|
2020-03-19 23:44:53 -04:00
|
|
|
}
|
2020-04-07 00:04:19 -04:00
|
|
|
v if v.is_special_function() => {
|
|
|
|
return Ok(Value::Ident(
|
2020-04-12 19:37:12 -04:00
|
|
|
format!(
|
|
|
|
"hsl({}, {}, {}, {})",
|
|
|
|
hue,
|
|
|
|
saturation,
|
|
|
|
lightness,
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
),
|
2020-04-07 00:04:19 -04:00
|
|
|
QuoteKind::None,
|
|
|
|
));
|
|
|
|
}
|
2020-04-12 19:37:12 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!("$alpha: {} is not a number.", v.to_css_string(args.span())?),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-19 23:44:53 -04:00
|
|
|
};
|
2020-04-21 18:54:19 -04:00
|
|
|
Ok(Value::Color(Box::new(Color::from_hsla(
|
2020-03-23 12:52:23 -04:00
|
|
|
hue, saturation, lightness, alpha,
|
2020-04-21 18:54:19 -04:00
|
|
|
))))
|
2020-03-19 23:44:53 -04:00
|
|
|
}
|
2020-03-16 10:35:38 -04:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
f.insert(
|
|
|
|
"hsla".to_owned(),
|
2020-04-04 18:17:04 -04:00
|
|
|
Builtin::new(|mut args, scope, super_selector| {
|
2020-03-22 23:41:02 -04:00
|
|
|
if args.is_empty() {
|
2020-04-12 19:37:12 -04:00
|
|
|
return Err(("Missing argument $channels.", args.span()).into());
|
2020-03-22 23:41:02 -04:00
|
|
|
}
|
|
|
|
|
2020-03-19 23:44:53 -04:00
|
|
|
if args.len() == 1 {
|
2020-04-04 18:17:04 -04:00
|
|
|
let mut channels = match arg!(args, scope, super_selector, 0, "channels") {
|
2020-03-23 19:56:24 -04:00
|
|
|
Value::List(v, ..) => v,
|
2020-04-12 19:37:12 -04:00
|
|
|
_ => return Err(("Missing argument $channels.", args.span()).into()),
|
2020-03-19 23:44:53 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
if channels.len() > 3 {
|
2020-04-12 19:37:12 -04:00
|
|
|
return Err((
|
|
|
|
format!(
|
|
|
|
"Only 3 elements allowed, but {} were passed.",
|
|
|
|
channels.len()
|
|
|
|
),
|
|
|
|
args.span(),
|
2020-03-19 23:44:53 -04:00
|
|
|
)
|
2020-04-12 19:37:12 -04:00
|
|
|
.into());
|
2020-03-16 10:35:38 -04:00
|
|
|
}
|
2020-03-19 23:44:53 -04:00
|
|
|
|
2020-03-23 12:52:23 -04:00
|
|
|
let lightness = match channels.pop() {
|
2020-03-19 23:44:53 -04:00
|
|
|
Some(Value::Dimension(n, _)) => n / Number::from(100),
|
2020-04-12 19:37:12 -04:00
|
|
|
Some(v) => {
|
|
|
|
return Err((
|
|
|
|
format!(
|
|
|
|
"$lightness: {} is not a number.",
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
|
|
|
None => return Err(("Missing element $lightness.", args.span()).into()),
|
2020-03-19 23:44:53 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
let saturation = match channels.pop() {
|
|
|
|
Some(Value::Dimension(n, _)) => n / Number::from(100),
|
2020-04-12 19:37:12 -04:00
|
|
|
Some(v) => {
|
|
|
|
return Err((
|
|
|
|
format!(
|
|
|
|
"$saturation: {} is not a number.",
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
|
|
|
None => return Err(("Missing element $saturation.", args.span()).into()),
|
2020-03-19 23:44:53 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
let hue = match channels.pop() {
|
|
|
|
Some(Value::Dimension(n, _)) => n,
|
2020-04-12 19:37:12 -04:00
|
|
|
Some(v) => {
|
|
|
|
return Err((
|
|
|
|
format!("$hue: {} is not a number.", v.to_css_string(args.span())?),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
|
|
|
None => return Err(("Missing element $hue.", args.span()).into()),
|
2020-03-19 23:44:53 -04:00
|
|
|
};
|
|
|
|
|
2020-04-21 18:54:19 -04:00
|
|
|
Ok(Value::Color(Box::new(Color::from_hsla(
|
2020-03-19 23:44:53 -04:00
|
|
|
hue,
|
|
|
|
saturation,
|
2020-03-23 12:52:23 -04:00
|
|
|
lightness,
|
2020-03-22 22:28:54 -04:00
|
|
|
Number::one(),
|
2020-04-21 18:54:19 -04:00
|
|
|
))))
|
2020-03-19 23:44:53 -04:00
|
|
|
} else {
|
2020-04-04 18:17:04 -04:00
|
|
|
let hue = match arg!(args, scope, super_selector, 0, "hue") {
|
2020-03-19 23:44:53 -04:00
|
|
|
Value::Dimension(n, _) => n,
|
2020-04-06 23:38:17 -04:00
|
|
|
v if v.is_special_function() => {
|
|
|
|
let saturation = arg!(args, scope, super_selector, 1, "saturation");
|
|
|
|
let lightness = arg!(args, scope, super_selector, 2, "lightness");
|
2020-04-12 19:37:12 -04:00
|
|
|
let mut string = format!(
|
|
|
|
"hsla({}, {}, {}",
|
|
|
|
v.to_css_string(args.span())?,
|
|
|
|
saturation.to_css_string(args.span())?,
|
|
|
|
lightness.to_css_string(args.span())?
|
|
|
|
);
|
2020-04-06 23:38:17 -04:00
|
|
|
if !args.is_empty() {
|
|
|
|
string.push_str(", ");
|
|
|
|
string.push_str(
|
2020-04-12 19:37:12 -04:00
|
|
|
&arg!(args, scope, super_selector, 3, "alpha")
|
|
|
|
.to_css_string(args.span())?,
|
2020-04-06 23:38:17 -04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
string.push(')');
|
|
|
|
return Ok(Value::Ident(string, QuoteKind::None));
|
|
|
|
}
|
2020-04-12 19:37:12 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!("$hue: {} is not a number.", v.to_css_string(args.span())?),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-19 23:44:53 -04:00
|
|
|
};
|
2020-04-04 18:17:04 -04:00
|
|
|
let saturation = match arg!(args, scope, super_selector, 1, "saturation") {
|
2020-03-19 23:44:53 -04:00
|
|
|
Value::Dimension(n, _) => n / Number::from(100),
|
2020-04-06 23:38:17 -04:00
|
|
|
v if v.is_special_function() => {
|
|
|
|
let lightness = arg!(args, scope, super_selector, 2, "lightness");
|
2020-04-12 19:37:12 -04:00
|
|
|
let mut string = format!(
|
|
|
|
"hsla({}, {}, {}",
|
|
|
|
hue,
|
|
|
|
v.to_css_string(args.span())?,
|
|
|
|
lightness.to_css_string(args.span())?
|
|
|
|
);
|
2020-04-06 23:38:17 -04:00
|
|
|
if !args.is_empty() {
|
|
|
|
string.push_str(", ");
|
|
|
|
string.push_str(
|
2020-04-12 19:37:12 -04:00
|
|
|
&arg!(args, scope, super_selector, 3, "alpha")
|
|
|
|
.to_css_string(args.span())?,
|
2020-04-06 23:38:17 -04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
string.push(')');
|
|
|
|
return Ok(Value::Ident(string, QuoteKind::None));
|
|
|
|
}
|
2020-04-12 19:37:12 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!(
|
|
|
|
"$saturation: {} is not a number.",
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-19 23:44:53 -04:00
|
|
|
};
|
2020-04-04 18:17:04 -04:00
|
|
|
let lightness = match arg!(args, scope, super_selector, 2, "lightness") {
|
2020-03-19 23:44:53 -04:00
|
|
|
Value::Dimension(n, _) => n / Number::from(100),
|
2020-04-06 23:38:17 -04:00
|
|
|
v if v.is_special_function() => {
|
2020-04-12 19:37:12 -04:00
|
|
|
let mut string = format!(
|
|
|
|
"hsla({}, {}, {}",
|
|
|
|
hue,
|
|
|
|
saturation,
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
);
|
2020-04-06 23:38:17 -04:00
|
|
|
if !args.is_empty() {
|
|
|
|
string.push_str(", ");
|
|
|
|
string.push_str(
|
2020-04-12 19:37:12 -04:00
|
|
|
&arg!(args, scope, super_selector, 3, "alpha")
|
|
|
|
.to_css_string(args.span())?,
|
2020-04-06 23:38:17 -04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
string.push(')');
|
|
|
|
return Ok(Value::Ident(string, QuoteKind::None));
|
|
|
|
}
|
2020-04-12 19:37:12 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!(
|
|
|
|
"$lightness: {} is not a number.",
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-19 23:44:53 -04:00
|
|
|
};
|
|
|
|
let alpha = match arg!(
|
|
|
|
args,
|
2020-04-04 18:17:04 -04:00
|
|
|
scope,
|
|
|
|
super_selector,
|
2020-03-19 23:44:53 -04:00
|
|
|
3,
|
2020-03-22 22:28:54 -04:00
|
|
|
"alpha" = Value::Dimension(Number::one(), Unit::None)
|
2020-03-19 23:44:53 -04:00
|
|
|
) {
|
|
|
|
Value::Dimension(n, Unit::None) => n,
|
|
|
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
|
|
|
v @ Value::Dimension(..) => {
|
2020-04-12 19:37:12 -04:00
|
|
|
return Err((
|
|
|
|
format!(
|
|
|
|
"$alpha: Expected {} to have no units or \"%\".",
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
),
|
|
|
|
args.span(),
|
2020-03-19 23:44:53 -04:00
|
|
|
)
|
2020-04-12 19:37:12 -04:00
|
|
|
.into())
|
2020-03-19 23:44:53 -04:00
|
|
|
}
|
2020-04-07 00:04:19 -04:00
|
|
|
v if v.is_special_function() => {
|
|
|
|
return Ok(Value::Ident(
|
2020-04-12 19:37:12 -04:00
|
|
|
format!(
|
|
|
|
"hsl({}, {}, {}, {})",
|
|
|
|
hue,
|
|
|
|
saturation,
|
|
|
|
lightness,
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
),
|
2020-04-07 00:04:19 -04:00
|
|
|
QuoteKind::None,
|
|
|
|
));
|
|
|
|
}
|
2020-04-12 19:37:12 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!("$alpha: {} is not a number.", v.to_css_string(args.span())?),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-19 23:44:53 -04:00
|
|
|
};
|
2020-04-21 18:54:19 -04:00
|
|
|
Ok(Value::Color(Box::new(Color::from_hsla(
|
2020-03-23 12:52:23 -04:00
|
|
|
hue, saturation, lightness, alpha,
|
2020-04-21 18:54:19 -04:00
|
|
|
))))
|
2020-03-19 23:44:53 -04:00
|
|
|
}
|
2020-03-16 10:35:38 -04:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
f.insert(
|
|
|
|
"hue".to_owned(),
|
2020-04-04 18:17:04 -04:00
|
|
|
Builtin::new(|mut args, scope, super_selector| {
|
2020-04-22 06:17:52 -04:00
|
|
|
args.max_args(1)?;
|
2020-04-04 18:17:04 -04:00
|
|
|
match arg!(args, scope, super_selector, 0, "color") {
|
2020-03-16 10:35:38 -04:00
|
|
|
Value::Color(c) => Ok(Value::Dimension(c.hue(), Unit::Deg)),
|
2020-04-12 19:37:12 -04:00
|
|
|
v => Err((
|
|
|
|
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into()),
|
2020-03-16 10:35:38 -04:00
|
|
|
}
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
f.insert(
|
|
|
|
"saturation".to_owned(),
|
2020-04-04 18:17:04 -04:00
|
|
|
Builtin::new(|mut args, scope, super_selector| {
|
2020-04-22 06:17:52 -04:00
|
|
|
args.max_args(1)?;
|
2020-04-04 18:17:04 -04:00
|
|
|
match arg!(args, scope, super_selector, 0, "color") {
|
2020-03-16 10:35:38 -04:00
|
|
|
Value::Color(c) => Ok(Value::Dimension(c.saturation(), Unit::Percent)),
|
2020-04-12 19:37:12 -04:00
|
|
|
v => Err((
|
|
|
|
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into()),
|
2020-03-16 10:35:38 -04:00
|
|
|
}
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
f.insert(
|
|
|
|
"lightness".to_owned(),
|
2020-04-04 18:17:04 -04:00
|
|
|
Builtin::new(|mut args, scope, super_selector| {
|
2020-04-22 06:17:52 -04:00
|
|
|
args.max_args(1)?;
|
2020-04-04 18:17:04 -04:00
|
|
|
match arg!(args, scope, super_selector, 0, "color") {
|
2020-03-16 10:35:38 -04:00
|
|
|
Value::Color(c) => Ok(Value::Dimension(c.lightness(), Unit::Percent)),
|
2020-04-12 19:37:12 -04:00
|
|
|
v => Err((
|
|
|
|
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into()),
|
2020-03-16 10:35:38 -04:00
|
|
|
}
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
f.insert(
|
|
|
|
"adjust-hue".to_owned(),
|
2020-04-04 18:17:04 -04:00
|
|
|
Builtin::new(|mut args, scope, super_selector| {
|
2020-04-22 06:17:52 -04:00
|
|
|
args.max_args(2)?;
|
2020-04-04 18:17:04 -04:00
|
|
|
let color = match arg!(args, scope, super_selector, 0, "color") {
|
2020-03-16 10:35:38 -04:00
|
|
|
Value::Color(c) => c,
|
2020-04-12 19:37:12 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-16 10:35:38 -04:00
|
|
|
};
|
2020-04-04 18:17:04 -04:00
|
|
|
let degrees = match arg!(args, scope, super_selector, 1, "degrees") {
|
2020-03-16 10:35:38 -04:00
|
|
|
Value::Dimension(n, _) => n,
|
2020-04-12 19:37:12 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!(
|
|
|
|
"$degrees: {} is not a number.",
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-16 10:35:38 -04:00
|
|
|
};
|
2020-04-21 18:54:19 -04:00
|
|
|
Ok(Value::Color(Box::new(color.adjust_hue(degrees))))
|
2020-03-16 10:35:38 -04:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
f.insert(
|
|
|
|
"lighten".to_owned(),
|
2020-04-04 18:17:04 -04:00
|
|
|
Builtin::new(|mut args, scope, super_selector| {
|
2020-04-22 06:17:52 -04:00
|
|
|
args.max_args(2)?;
|
2020-04-04 18:17:04 -04:00
|
|
|
let color = match arg!(args, scope, super_selector, 0, "color") {
|
2020-03-16 10:35:38 -04:00
|
|
|
Value::Color(c) => c,
|
2020-04-12 19:37:12 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-16 10:35:38 -04:00
|
|
|
};
|
2020-04-04 18:17:04 -04:00
|
|
|
let amount = match arg!(args, scope, super_selector, 1, "amount") {
|
2020-04-12 19:37:12 -04:00
|
|
|
Value::Dimension(n, u) => bound!(args, "amount", n, u, 0, 100) / Number::from(100),
|
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!(
|
|
|
|
"$amount: {} is not a number.",
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-16 10:35:38 -04:00
|
|
|
};
|
2020-04-21 18:54:19 -04:00
|
|
|
Ok(Value::Color(Box::new(color.lighten(amount))))
|
2020-03-16 10:35:38 -04:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
f.insert(
|
|
|
|
"darken".to_owned(),
|
2020-04-04 18:17:04 -04:00
|
|
|
Builtin::new(|mut args, scope, super_selector| {
|
2020-04-22 06:17:52 -04:00
|
|
|
args.max_args(2)?;
|
2020-04-04 18:17:04 -04:00
|
|
|
let color = match arg!(args, scope, super_selector, 0, "color") {
|
2020-03-16 10:35:38 -04:00
|
|
|
Value::Color(c) => c,
|
2020-04-12 19:37:12 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-16 10:35:38 -04:00
|
|
|
};
|
2020-04-04 18:17:04 -04:00
|
|
|
let amount = match arg!(args, scope, super_selector, 1, "amount") {
|
2020-04-12 19:37:12 -04:00
|
|
|
Value::Dimension(n, u) => bound!(args, "amount", n, u, 0, 100) / Number::from(100),
|
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!(
|
|
|
|
"$amount: {} is not a number.",
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-16 10:35:38 -04:00
|
|
|
};
|
2020-04-21 18:54:19 -04:00
|
|
|
Ok(Value::Color(Box::new(color.darken(amount))))
|
2020-03-16 10:35:38 -04:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
f.insert(
|
|
|
|
"saturate".to_owned(),
|
2020-04-04 18:17:04 -04:00
|
|
|
Builtin::new(|mut args, scope, super_selector| {
|
2020-04-22 06:17:52 -04:00
|
|
|
args.max_args(2)?;
|
2020-03-22 23:28:19 -04:00
|
|
|
if args.len() == 1 {
|
2020-03-22 23:41:02 -04:00
|
|
|
return Ok(Value::Ident(
|
2020-04-04 18:17:04 -04:00
|
|
|
format!(
|
|
|
|
"saturate({})",
|
|
|
|
arg!(args, scope, super_selector, 0, "amount")
|
2020-04-12 19:37:12 -04:00
|
|
|
.to_css_string(args.span())?
|
2020-04-04 18:17:04 -04:00
|
|
|
),
|
2020-03-22 23:41:02 -04:00
|
|
|
QuoteKind::None,
|
|
|
|
));
|
2020-03-22 23:28:19 -04:00
|
|
|
}
|
|
|
|
|
2020-04-04 18:17:04 -04:00
|
|
|
let amount = match arg!(args, scope, super_selector, 1, "amount") {
|
2020-04-12 19:37:12 -04:00
|
|
|
Value::Dimension(n, u) => bound!(args, "amount", n, u, 0, 100) / Number::from(100),
|
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!(
|
|
|
|
"$amount: {} is not a number.",
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-16 10:35:38 -04:00
|
|
|
};
|
2020-04-04 18:17:04 -04:00
|
|
|
let color = match arg!(args, scope, super_selector, 0, "color") {
|
2020-03-16 10:35:38 -04:00
|
|
|
Value::Color(c) => c,
|
|
|
|
Value::Dimension(n, u) => {
|
|
|
|
return Ok(Value::Ident(
|
|
|
|
format!("saturate({}{})", n, u),
|
|
|
|
QuoteKind::None,
|
|
|
|
))
|
|
|
|
}
|
2020-04-12 19:37:12 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-16 10:35:38 -04:00
|
|
|
};
|
2020-04-21 18:54:19 -04:00
|
|
|
Ok(Value::Color(Box::new(color.saturate(amount))))
|
2020-03-16 10:35:38 -04:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
f.insert(
|
|
|
|
"desaturate".to_owned(),
|
2020-04-04 18:17:04 -04:00
|
|
|
Builtin::new(|mut args, scope, super_selector| {
|
2020-04-22 06:17:52 -04:00
|
|
|
args.max_args(2)?;
|
2020-04-04 18:17:04 -04:00
|
|
|
let color = match arg!(args, scope, super_selector, 0, "color") {
|
2020-03-16 10:35:38 -04:00
|
|
|
Value::Color(c) => c,
|
2020-04-12 19:37:12 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-16 10:35:38 -04:00
|
|
|
};
|
2020-04-04 18:17:04 -04:00
|
|
|
let amount = match arg!(args, scope, super_selector, 1, "amount") {
|
2020-04-12 19:37:12 -04:00
|
|
|
Value::Dimension(n, u) => bound!(args, "amount", n, u, 0, 100) / Number::from(100),
|
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!(
|
|
|
|
"$amount: {} is not a number.",
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-16 10:35:38 -04:00
|
|
|
};
|
2020-04-21 18:54:19 -04:00
|
|
|
Ok(Value::Color(Box::new(color.desaturate(amount))))
|
2020-03-16 10:35:38 -04:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
f.insert(
|
|
|
|
"grayscale".to_owned(),
|
2020-04-04 18:17:04 -04:00
|
|
|
Builtin::new(|mut args, scope, super_selector| {
|
2020-04-22 06:17:52 -04:00
|
|
|
args.max_args(1)?;
|
2020-04-04 18:17:04 -04:00
|
|
|
let color = match arg!(args, scope, super_selector, 0, "color") {
|
2020-03-16 10:35:38 -04:00
|
|
|
Value::Color(c) => c,
|
|
|
|
Value::Dimension(n, u) => {
|
|
|
|
return Ok(Value::Ident(
|
|
|
|
format!("grayscale({}{})", n, u),
|
|
|
|
QuoteKind::None,
|
|
|
|
))
|
|
|
|
}
|
2020-04-12 19:37:12 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-16 10:35:38 -04:00
|
|
|
};
|
2020-04-21 18:54:19 -04:00
|
|
|
Ok(Value::Color(Box::new(color.desaturate(Number::one()))))
|
2020-03-16 10:35:38 -04:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
f.insert(
|
|
|
|
"complement".to_owned(),
|
2020-04-04 18:17:04 -04:00
|
|
|
Builtin::new(|mut args, scope, super_selector| {
|
2020-04-22 06:17:52 -04:00
|
|
|
args.max_args(1)?;
|
2020-04-04 18:17:04 -04:00
|
|
|
let color = match arg!(args, scope, super_selector, 0, "color") {
|
2020-03-16 10:35:38 -04:00
|
|
|
Value::Color(c) => c,
|
2020-04-12 19:37:12 -04:00
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-16 10:35:38 -04:00
|
|
|
};
|
2020-04-21 18:54:19 -04:00
|
|
|
Ok(Value::Color(Box::new(color.complement())))
|
2020-03-16 10:35:38 -04:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
f.insert(
|
|
|
|
"invert".to_owned(),
|
2020-04-04 18:17:04 -04:00
|
|
|
Builtin::new(|mut args, scope, super_selector| {
|
2020-04-22 06:17:52 -04:00
|
|
|
args.max_args(2)?;
|
2020-03-16 10:35:38 -04:00
|
|
|
let weight = match arg!(
|
|
|
|
args,
|
2020-04-04 18:17:04 -04:00
|
|
|
scope,
|
|
|
|
super_selector,
|
2020-03-16 10:35:38 -04:00
|
|
|
1,
|
|
|
|
"weight" = Value::Dimension(Number::from(100), Unit::Percent)
|
|
|
|
) {
|
2020-04-12 19:37:12 -04:00
|
|
|
Value::Dimension(n, u) => bound!(args, "weight", n, u, 0, 100) / Number::from(100),
|
|
|
|
v => {
|
|
|
|
return Err((
|
|
|
|
format!(
|
|
|
|
"$weight: {} is not a number.",
|
|
|
|
v.to_css_string(args.span())?
|
|
|
|
),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into())
|
|
|
|
}
|
2020-03-16 10:35:38 -04:00
|
|
|
};
|
2020-04-04 18:17:04 -04:00
|
|
|
match arg!(args, scope, super_selector, 0, "color") {
|
2020-04-21 18:54:19 -04:00
|
|
|
Value::Color(c) => Ok(Value::Color(Box::new(c.invert(weight)))),
|
2020-03-16 10:35:38 -04:00
|
|
|
Value::Dimension(n, Unit::Percent) => {
|
|
|
|
Ok(Value::Ident(format!("invert({}%)", n), QuoteKind::None))
|
|
|
|
}
|
2020-04-12 19:37:12 -04:00
|
|
|
Value::Dimension(..) => Err((
|
|
|
|
"Only one argument may be passed to the plain-CSS invert() function.",
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into()),
|
|
|
|
v => Err((
|
|
|
|
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
|
|
|
|
args.span(),
|
|
|
|
)
|
|
|
|
.into()),
|
2020-03-16 10:35:38 -04:00
|
|
|
}
|
|
|
|
}),
|
|
|
|
);
|
2020-02-14 14:23:54 -05:00
|
|
|
}
|