Implement builtin function lighten()

This commit is contained in:
ConnorSkees 2020-02-14 08:43:10 -05:00
parent 6427a7ab81
commit db8e8eaebb
3 changed files with 77 additions and 5 deletions

View File

@ -175,8 +175,20 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
Value::Dimension(n, Unit::None) Value::Dimension(n, Unit::None)
| Value::Dimension(n, Unit::Percent) | Value::Dimension(n, Unit::Percent)
| Value::Dimension(n, Unit::Deg) => n, | Value::Dimension(n, Unit::Deg) => n,
_ => todo!("expected either unitless or % number for alpha"), _ => todo!("expected either unitless or % number for degrees"),
}; };
Some(Value::Color(color.adjust_hue(degrees))) Some(Value::Color(color.adjust_hue(degrees)))
}); });
decl!(f "lighten", |args, _| {
let color = match arg!(args, 0, "color").eval() {
Value::Color(c) => c,
_ => todo!("non-color given to builtin function `lighten()`")
};
let amount = match arg!(args, 1, "amount").eval() {
Value::Dimension(n, Unit::None) => n,
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
_ => todo!("expected either unitless or % number for amount"),
};
Some(Value::Color(color.lighten(amount)))
});
} }

View File

@ -102,11 +102,54 @@ impl Color {
(((min + max) / Number::from(2)) * Number::from(100)).round() (((min + max) / Number::from(2)) * Number::from(100)).round()
} }
pub fn as_hsla(&self) -> (Number, Number, Number, Number) {
let red = self.red.clone() / Number::from(255);
let green = self.green.clone() / Number::from(255);
let blue = self.blue.clone() / Number::from(255);
let min = red.clone().min(green.clone().min(blue.clone()));
let max = red.clone().max(green.clone().max(blue.clone()));
let lightness = (min.clone() + max.clone()) / Number::from(2);
let saturation = if &min == &max {
Number::from(0)
} else {
let d = max.clone() - min.clone();
let mm = max.clone() + min.clone();
d / if mm > Number::from(1) {
Number::from(2) - mm
} else {
mm
}
};
let mut hue = if min == max {
Number::from(0)
} else if red == max {
(green - blue) / (max - min)
} else if green == max {
Number::from(2) + (blue - red) / (max - min)
} else {
Number::from(4) + (red - green) / (max - min)
};
if hue < Number::from(0) {
hue += Number::from(360);
}
hue *= Number::from(60);
(hue, saturation, lightness, self.alpha())
}
pub fn adjust_hue(&self, degrees: Number) -> Self { pub fn adjust_hue(&self, degrees: Number) -> Self {
let hue = self.hue(); let (hue, saturation, luminance, alpha) = self.as_hsla();
let saturation = Number::ratio(self.saturation(), 100); Color::from_hsla(hue + degrees, saturation, luminance, alpha)
let luminance = Number::ratio(self.lightness(), 100); }
Color::from_hsla(hue + degrees, saturation, luminance, self.alpha())
pub fn lighten(&self, amount: Number) -> Self {
let (hue, saturation, luminance, alpha) = self.as_hsla();
Color::from_hsla(hue, saturation, luminance + amount, alpha)
} }
pub fn alpha(&self) -> Number { pub fn alpha(&self) -> Number {

View File

@ -217,3 +217,20 @@ test!(
// "a {\n color: adjust-hue($color: hsl(120, 30%, 90%), $degrees: 60deg);\n}\n", // "a {\n color: adjust-hue($color: hsl(120, 30%, 90%), $degrees: 60deg);\n}\n",
// "a {\n color: #deeded;\n}\n" // "a {\n color: #deeded;\n}\n"
// ); // );
// test!(
// lighten_named_args,
// "a {\n color: lighten($color: hsl(0, 0%, 0%), $amount: 30%);\n}\n",
// "a {\n color: #deeded;\n}\n"
// );
test!(
lighten_basic,
"a {\n color: lighten(hsl(0, 0%, 0%), 30%);\n}\n",
"a {\n color: #4d4d4d;\n}\n"
);
test!(
lighten_3_hex,
"a {\n color: lighten(#800, 20%);\n}\n",
// eventually, this should become `#e00`
// blocked on recognizing when to use 3-hex over 6-hex
"a {\n color: #ee0000;\n}\n"
);