Handle percentages and large/small values inside rgb()
and rgba()
This commit is contained in:
parent
3d0d37bf2d
commit
901c911b5b
@ -13,10 +13,22 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
decl!(f "rgb", |args, _| {
|
decl!(f "rgb", |args, _| {
|
||||||
let channels = args.get("channels").unwrap_or(&Value::Null);
|
let channels = args.get("channels").unwrap_or(&Value::Null);
|
||||||
if channels.is_null() {
|
if channels.is_null() {
|
||||||
let red: u16 = arg!(args, 0, "red").clone().try_into().unwrap();
|
let red = match arg!(args, 0, "red").clone().eval() {
|
||||||
let green: u16 = arg!(args, 1, "green").clone().try_into().unwrap();
|
Value::Dimension(n, Unit::None) => n,
|
||||||
let blue: u16 = arg!(args, 2, "blue").clone().try_into().unwrap();
|
Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
|
||||||
Some(Value::Color(Color::from_values(red, green, blue, Number::from(1))))
|
_ => todo!("expected either unitless or % number for alpha"),
|
||||||
|
};
|
||||||
|
let green = match arg!(args, 1, "green").clone().eval() {
|
||||||
|
Value::Dimension(n, Unit::None) => n,
|
||||||
|
Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
|
||||||
|
_ => todo!("expected either unitless or % number for alpha"),
|
||||||
|
};
|
||||||
|
let blue = match arg!(args, 2, "blue").clone().eval() {
|
||||||
|
Value::Dimension(n, Unit::None) => n,
|
||||||
|
Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
|
||||||
|
_ => todo!("expected either unitless or % number for alpha"),
|
||||||
|
};
|
||||||
|
Some(Value::Color(Color::from_rgba(red, green, blue, Number::from(1))))
|
||||||
} else {
|
} else {
|
||||||
todo!("channels variable in `rgb`")
|
todo!("channels variable in `rgb`")
|
||||||
}
|
}
|
||||||
@ -24,15 +36,27 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
|
|||||||
decl!(f "rgba", |args, _| {
|
decl!(f "rgba", |args, _| {
|
||||||
let channels = args.get("channels").unwrap_or(&Value::Null);
|
let channels = args.get("channels").unwrap_or(&Value::Null);
|
||||||
if channels.is_null() {
|
if channels.is_null() {
|
||||||
let red: u16 = arg!(args, 0, "red").clone().try_into().unwrap();
|
let red = match arg!(args, 0, "red").clone().eval() {
|
||||||
let green: u16 = arg!(args, 1, "green").clone().try_into().unwrap();
|
Value::Dimension(n, Unit::None) => n,
|
||||||
let blue: u16 = arg!(args, 2, "blue").clone().try_into().unwrap();
|
Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
|
||||||
|
_ => todo!("expected either unitless or % number for alpha"),
|
||||||
|
};
|
||||||
|
let green = match arg!(args, 1, "green").clone().eval() {
|
||||||
|
Value::Dimension(n, Unit::None) => n,
|
||||||
|
Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
|
||||||
|
_ => todo!("expected either unitless or % number for alpha"),
|
||||||
|
};
|
||||||
|
let blue = match arg!(args, 2, "blue").clone().eval() {
|
||||||
|
Value::Dimension(n, Unit::None) => n,
|
||||||
|
Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
|
||||||
|
_ => todo!("expected either unitless or % number for alpha"),
|
||||||
|
};
|
||||||
let alpha = match arg!(args, 3, "alpha").clone().eval() {
|
let alpha = match arg!(args, 3, "alpha").clone().eval() {
|
||||||
Value::Dimension(n, Unit::None) => n,
|
Value::Dimension(n, Unit::None) => n,
|
||||||
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
Value::Dimension(n, Unit::Percent) => n / Number::from(100),
|
||||||
_ => todo!("expected either unitless or % number for alpha"),
|
_ => todo!("expected either unitless or % number for alpha"),
|
||||||
};
|
};
|
||||||
Some(Value::Color(Color::from_values(red, green, blue, alpha)))
|
Some(Value::Color(Color::from_rgba(red, green, blue, alpha)))
|
||||||
} else {
|
} else {
|
||||||
todo!("channels variable in `rgba`")
|
todo!("channels variable in `rgba`")
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,23 @@ impl Color {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_values(red: u16, green: u16, blue: u16, alpha: Number) -> Self {
|
pub fn from_rgba(red: Number, green: Number, blue: Number, alpha: Number) -> Self {
|
||||||
|
macro_rules! clamp {
|
||||||
|
($channel:ident) => {
|
||||||
|
let $channel = if $channel > Number::from(255) {
|
||||||
|
255_u16
|
||||||
|
} else if $channel < Number::from(0) {
|
||||||
|
0_u16
|
||||||
|
} else {
|
||||||
|
$channel.round().to_integer().to_u16().unwrap()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
clamp!(red);
|
||||||
|
clamp!(green);
|
||||||
|
clamp!(blue);
|
||||||
|
|
||||||
let repr = if alpha < Number::from(1) {
|
let repr = if alpha < Number::from(1) {
|
||||||
format!("rgba({}, {}, {}, {})", red, green, blue, alpha)
|
format!("rgba({}, {}, {}, {})", red, green, blue, alpha)
|
||||||
} else if let Ok(c) = ColorName::try_from([red, green, blue]) {
|
} else if let Ok(c) = ColorName::try_from([red, green, blue]) {
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
#![allow(dead_code, unused_variables)]
|
#![allow(dead_code, unused_variables)]
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
|
|
||||||
use num_bigint::BigInt;
|
|
||||||
|
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use crate::common::{ListSeparator, Op, QuoteKind};
|
use crate::common::{ListSeparator, Op, QuoteKind};
|
||||||
use crate::units::Unit;
|
use crate::units::Unit;
|
||||||
@ -52,25 +49,6 @@ impl Display for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryInto<u16> for Value {
|
|
||||||
type Error = &'static str;
|
|
||||||
fn try_into(self) -> Result<u16, Self::Error> {
|
|
||||||
match self {
|
|
||||||
Self::BinaryOp(..) => self.eval().try_into(),
|
|
||||||
Self::Dimension(n, Unit::Percent) => todo!(),
|
|
||||||
Self::Dimension(n, Unit::None) => {
|
|
||||||
if n >= Number::from(BigInt::from(255)) {
|
|
||||||
Ok(255)
|
|
||||||
} else {
|
|
||||||
Ok(n.to_integer().to_str_radix(10).parse().unwrap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Self::Dimension(n, _) => Err("Expected `val` to have no units or \"%\"."),
|
|
||||||
_ => Err("expected number"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
pub fn is_null(&self) -> bool {
|
pub fn is_null(&self) -> bool {
|
||||||
self == &Value::Null
|
self == &Value::Null
|
||||||
|
@ -46,6 +46,16 @@ test!(
|
|||||||
"a {\n color: rgb(1, 2, 3);\n}\n",
|
"a {\n color: rgb(1, 2, 3);\n}\n",
|
||||||
"a {\n color: #010203;\n}\n"
|
"a {\n color: #010203;\n}\n"
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
rgba_percent,
|
||||||
|
"a {\n color: rgba(159%, 169, 169%, 50%);\n}\n",
|
||||||
|
"a {\n color: rgba(255, 169, 255, 0.5);\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
rgba_percent_round_up,
|
||||||
|
"a {\n color: rgba(59%, 169, 69%, 50%);\n}\n",
|
||||||
|
"a {\n color: rgba(150, 169, 176, 0.5);\n}\n"
|
||||||
|
);
|
||||||
test!(
|
test!(
|
||||||
rgb_double_digits,
|
rgb_double_digits,
|
||||||
"a {\n color: rgb(254, 255, 255);\n}\n",
|
"a {\n color: rgb(254, 255, 255);\n}\n",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user