Skip to content

Commit

Permalink
Some fixes for hsl colors.
Browse files Browse the repository at this point in the history
  • Loading branch information
kaj committed Sep 14, 2024
1 parent e33e570 commit 039d315
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 79 deletions.
4 changes: 2 additions & 2 deletions rsass/src/sass/functions/color/hsl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::output::Format;
use crate::sass::{ArgsError, FormalArgs, Name};
use crate::value::{Color, Hsla, Numeric, Rational, Unit};
use crate::Scope;
use num_traits::zero;
use num_traits::{one, zero};

pub fn register(f: &mut Scope) {
def_va!(f, _hsl(kwargs), |s| do_hsla(&name!(hsl), s));
Expand Down Expand Up @@ -91,7 +91,7 @@ pub fn expose(m: &Scope, global: &mut FunctionMap) {
let col = s.get::<Color>(name!(color))?;
let sat = s.get_map(name!(amount), check_amount)?;
let col = col.to_hsla();
let sat = col.sat() + sat;
let sat = (col.sat() + sat).clamp(zero(), one());
Ok(Hsla::new(col.hue(), sat, col.lum(), col.alpha(), false)
.into())
}
Expand Down
115 changes: 67 additions & 48 deletions rsass/src/sass/functions/color/other.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,14 @@ pub fn register(f: &mut Scope) {
}
let rgba: Color = s.get(name!(color))?;
let mut args = s.get_map(name!(kwargs), CallArgs::from_value)?;
if !args.positional.is_empty() {
return Err(CallError::msg("Only one positional argument is allowed. \
All other arguments must be passed by name."));
}
no_more_positional(&args)?;
let a_adj = take_opt(&mut args, name!(alpha), check_alpha_pm)?;

let red = take_opt(&mut args, name!(red), check_channel_pm)?;
let gre = take_opt(&mut args, name!(green), check_channel_pm)?;
let blu = take_opt(&mut args, name!(blue), check_channel_pm)?;
let hue = take_opt(&mut args, name!(hue), check_hue)?;
let sat = take_opt(&mut args, name!(saturation), check_pct_pm)?;
let lig = take_opt(&mut args, name!(lightness), check_pct_pm)?;
let bla = take_opt(&mut args, name!(blackness), check_pct_expl_pm)?;
let whi = take_opt(&mut args, name!(whiteness), check_pct_expl_pm)?;
let a_adj = take_opt(&mut args, name!(alpha), check_alpha_pm)?;
args.check_no_named().map_err(CallError::msg)?;

if red.is_some() || gre.is_some() || blu.is_some() {
check_none(&[bla, whi], "RGB", "HWB")?;
check_none(&[hue, sat, lig], "RGB", "HSL")?;
no_more_in_space(&args, "rgb")?;
let rgba = rgba.to_rgba();
Ok(Rgba::new(
opt_add(rgba.red(), red),
Expand All @@ -46,26 +36,47 @@ pub fn register(f: &mut Scope) {
rgba.source(),
)
.into())
} else if bla.is_some() || whi.is_some() {
check_none(&[sat, lig], "HSL", "HWB")?;
let hwba = rgba.to_hwba();
Ok(Hwba::new(
opt_add(hwba.hue(), hue),
opt_add(hwba.whiteness(), whi),
opt_add(hwba.blackness(), bla),
opt_add(hwba.alpha(), a_adj),
)
.into())
} else {
let hsla = rgba.to_hsla();
Ok(Hsla::new(
opt_add(hsla.hue(), hue),
opt_add(hsla.sat(), sat),
opt_add(hsla.lum(), lig),
opt_add(hsla.alpha(), a_adj),
hsla.hsla_format,
)
.into())
let hue = take_opt(&mut args, name!(hue), check_hue)?;
let sat = take_opt(&mut args, name!(saturation), check_pct)?;
let lig = take_opt(&mut args, name!(lightness), check_pct)?;
if sat.is_some() || lig.is_some() {
no_more_in_space(&args, "hsl")?;
}
let bla =
take_opt(&mut args, name!(blackness), check_pct_expl_pm)?;
let whi =
take_opt(&mut args, name!(whiteness), check_pct_expl_pm)?;
args.check_no_named().map_err(CallError::msg)?;
if bla.is_some() || whi.is_some() {
let hwba = rgba.to_hwba();
Ok(Hwba::new(
opt_add(hwba.hue(), hue),
opt_add(hwba.whiteness(), whi),
opt_add(hwba.blackness(), bla),
opt_add(hwba.alpha(), a_adj),
)
.into())
} else if hue.is_some() || sat.is_some() || lig.is_some() {
let hsla = rgba.to_hsla();
let sat = opt_add(hsla.sat(), sat);
let lum = opt_add(hsla.lum(), lig);
Ok(Hsla::new(
opt_add(hsla.hue(), hue),
sat,
lum,
opt_add(hsla.alpha(), a_adj),
hsla.hsla_format
|| sat > one()
|| lum > one()
|| lum < zero(),
)
.into())
} else {
let mut rgba = rgba.clone();
rgba.set_alpha(opt_add(rgba.get_alpha(), a_adj));
Ok(rgba.into())
}
}
});
def_va!(f, scale(color, kwargs), |s| {
Expand All @@ -85,10 +96,7 @@ pub fn register(f: &mut Scope) {

let rgba: Color = s.get(name!(color))?;
let mut args = s.get_map(name!(kwargs), CallArgs::from_value)?;
if !args.positional.is_empty() {
return Err(CallError::msg("Only one positional argument is allowed. \
All other arguments must be passed by name."));
}
no_more_positional(&args)?;
let red = take_opt(&mut args, name!(red), check_pct_expl_pm)?;
let gre = take_opt(&mut args, name!(green), check_pct_expl_pm)?;
let blu = take_opt(&mut args, name!(blue), check_pct_expl_pm)?;
Expand Down Expand Up @@ -151,10 +159,7 @@ pub fn register(f: &mut Scope) {
def_va!(f, change(color, kwargs), |s| {
let rgba: Color = s.get(name!(color))?;
let mut args = s.get_map(name!(kwargs), CallArgs::from_value)?;
if !args.positional.is_empty() {
return Err(CallError::msg("Only one positional argument is allowed. \
All other arguments must be passed by name."));
}
no_more_positional(&args)?;
let red = take_opt(&mut args, name!(red), check_channel_range)?;
let gre = take_opt(&mut args, name!(green), check_channel_range)?;
let blu = take_opt(&mut args, name!(blue), check_channel_range)?;
Expand Down Expand Up @@ -256,6 +261,25 @@ fn check_none(
}
}

fn no_more_positional(args: &CallArgs) -> Result<(), CallError> {
if !args.positional.is_empty() {
Err(CallError::msg(
"Only one positional argument is allowed. \
All other arguments must be passed by name.",
))
} else {
Ok(())
}
}

fn no_more_in_space(args: &CallArgs, space: &str) -> Result<(), CallError> {
if let Some((name, _)) = args.named.iter().next() {
Err(CallError::msg(format!("${name}: Color space {space} doesn\'t have a channel with this name.")))
} else {
Ok(())
}
}

fn take_opt<T, F>(
args: &mut CallArgs,
name: Name,
Expand All @@ -267,13 +291,8 @@ where
args.named.remove(&name).map(check).transpose().named(name)
}

fn check_pct_pm(v: Value) -> Result<Rational, String> {
let val = Numeric::try_from(v)?;
if val.value.abs() > 100.into() {
Err(expected_to(val, "be within -100% and 100%"))
} else {
Ok(val.as_ratio()? / 100)
}
fn check_pct(v: Value) -> Result<Rational, String> {
Ok(Numeric::try_from(v)?.as_ratio()? / 100)
}
fn check_pct_expl_pm(v: Value) -> Result<Rational, String> {
let val = Numeric::try_from(v)?;
Expand Down
14 changes: 8 additions & 6 deletions rsass/src/value/colors/hsla.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ impl Hsla {
) -> Self {
Self {
hue: deg_mod(hue),
sat: sat.clamp(zero(), one()),
lum: lum.clamp(zero(), one()),
sat: sat.max(zero()),
lum,
alpha: alpha.clamp(zero(), one()),
hsla_format,
}
Expand Down Expand Up @@ -83,23 +83,25 @@ impl<'a> Display for Formatted<'a, Hsla> {
fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
let hsla = self.value;
let hue = Number::from(hsla.hue);
let sat = Number::from(hsla.sat * 100);
let lum = Number::from(hsla.lum * 100);
let a = hsla.alpha;
if a >= one() {
write!(
out,
"hsl({}, {}%, {}%)",
hue.format(self.format),
hsla.sat * 100,
hsla.lum * 100
sat.format(self.format),
lum.format(self.format),
)
} else {
let a = Number::from(a);
write!(
out,
"hsla({}, {}%, {}%, {})",
hue.format(self.format),
hsla.sat * 100,
hsla.lum * 100,
sat.format(self.format),
lum.format(self.format),
a.format(self.format)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ fn runner() -> crate::TestRunner {
}

#[test]
#[ignore] // wrong error
fn blue_and_lightness() {
assert_eq!(
runner().err(
Expand All @@ -22,7 +21,6 @@ fn blue_and_lightness() {
);
}
#[test]
#[ignore] // wrong error
fn green_and_saturation() {
assert_eq!(
runner().err(
Expand All @@ -38,7 +36,6 @@ fn green_and_saturation() {
);
}
#[test]
#[ignore] // wrong error
fn green_and_whiteness() {
assert_eq!(
runner().err(
Expand All @@ -54,7 +51,6 @@ fn green_and_whiteness() {
);
}
#[test]
#[ignore] // wrong error
fn lightness_and_whiteness() {
assert_eq!(
runner().err(
Expand All @@ -70,7 +66,6 @@ fn lightness_and_whiteness() {
);
}
#[test]
#[ignore] // wrong error
fn red_and_blackness() {
assert_eq!(
runner().err(
Expand All @@ -86,7 +81,6 @@ fn red_and_blackness() {
);
}
#[test]
#[ignore] // wrong error
fn red_and_hue() {
assert_eq!(
runner().err(
Expand All @@ -102,7 +96,6 @@ fn red_and_hue() {
);
}
#[test]
#[ignore] // wrong error
fn saturation_and_blackness() {
assert_eq!(
runner().err(
Expand Down
9 changes: 0 additions & 9 deletions rsass/tests/spec/core_functions/color/adjust/hsl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ mod lightness {
use super::runner;

#[test]
#[ignore] // wrong result
fn above_max() {
assert_eq!(
runner().ok("@use \"sass:color\";\
Expand All @@ -152,7 +151,6 @@ mod lightness {
);
}
#[test]
#[ignore] // unexepected error
fn arg_above_max() {
assert_eq!(
runner().ok("@use \"sass:color\";\
Expand All @@ -163,7 +161,6 @@ mod lightness {
);
}
#[test]
#[ignore] // unexepected error
fn arg_below_min() {
assert_eq!(
runner().ok("@use \"sass:color\";\
Expand All @@ -174,7 +171,6 @@ mod lightness {
);
}
#[test]
#[ignore] // wrong result
fn below_min() {
assert_eq!(
runner().ok("@use \"sass:color\";\
Expand Down Expand Up @@ -225,7 +221,6 @@ mod lightness {
);
}
#[test]
#[ignore] // wrong result
fn min() {
assert_eq!(
runner().ok("@use \"sass:color\";\
Expand Down Expand Up @@ -273,7 +268,6 @@ mod saturation {
use super::runner;

#[test]
#[ignore] // wrong result
fn above_max() {
assert_eq!(
runner().ok("@use \"sass:color\";\
Expand All @@ -284,7 +278,6 @@ mod saturation {
);
}
#[test]
#[ignore] // unexepected error
fn arg_above_max() {
assert_eq!(
runner().ok("@use \"sass:color\";\
Expand All @@ -295,7 +288,6 @@ mod saturation {
);
}
#[test]
#[ignore] // unexepected error
fn arg_below_min() {
assert_eq!(
runner().ok("@use \"sass:color\";\
Expand Down Expand Up @@ -336,7 +328,6 @@ mod saturation {
);
}
#[test]
#[ignore] // wrong result
fn max_remaining() {
assert_eq!(
runner().ok("@use \"sass:color\";\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ mod lightness {
}
}
#[test]
#[ignore] // wrong result
fn finite() {
assert_eq!(
runner().ok("a {b: hsl(0, 100%, 9999%, 0.5)}\n"),
Expand Down
1 change: 0 additions & 1 deletion rsass/tests/spec/core_functions/color/hsl/one_arg/alpha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ mod clamped {
}
}
#[test]
#[ignore] // wrong result
fn lightness() {
assert_eq!(
runner().ok("a {b: hsl(0 100% 9999% / 0.5)}\n"),
Expand Down
3 changes: 0 additions & 3 deletions rsass/tests/spec/core_functions/color/hsl/one_arg/no_alpha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ mod clamped {
use super::runner;

#[test]
#[ignore] // wrong result
fn above() {
assert_eq!(
runner().ok("a {b: hsl(0 100% 500%)}\n"),
Expand All @@ -24,7 +23,6 @@ mod clamped {
);
}
#[test]
#[ignore] // wrong result
fn below() {
assert_eq!(
runner().ok("a {b: hsl(0 100% -100%)}\n"),
Expand Down Expand Up @@ -139,7 +137,6 @@ mod out_of_gamut {
use super::runner;

#[test]
#[ignore] // wrong result
fn above() {
assert_eq!(
runner().ok("a {b: hsl(0 500% 50%)}\n"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ mod saturation {
use super::runner;

#[test]
#[ignore] // wrong result
fn above() {
assert_eq!(
runner().ok("a {b: hsl(0, 500%, 50%)}\n"),
Expand Down
Loading

0 comments on commit 039d315

Please sign in to comment.