From bef13ced9cbd7827e7776990d467bd729a63a45b Mon Sep 17 00:00:00 2001 From: Rasmus Kaj Date: Fri, 20 Sep 2024 20:56:39 +0200 Subject: [PATCH] Make all color channels f64. A color channel can now be NaN or infinite, so represent them as f64 rather than as rationals. This also makes the color structs smaller, as the rational numbers were 16 bytes each while a f64 is 8. --- CHANGELOG.md | 1 + rsass/src/sass/functions/color/hsl.rs | 25 ++-- rsass/src/sass/functions/color/hwb.rs | 19 ++- rsass/src/sass/functions/color/mod.rs | 73 +++++----- rsass/src/sass/functions/color/other.rs | 46 ++---- rsass/src/sass/functions/color/rgb.rs | 20 ++- rsass/src/value/colors/convert.rs | 90 ++++++------ rsass/src/value/colors/hsla.rs | 77 +++++----- rsass/src/value/colors/hwba.rs | 40 +++--- rsass/src/value/colors/mod.rs | 35 +++-- rsass/src/value/colors/rgba.rs | 133 ++++++++---------- .../spec/core_functions/color/adjust/hwb.rs | 2 - .../color/hsl/four_args/out_of_gamut.rs | 12 -- .../core_functions/color/hwb/four_args.rs | 19 +-- .../spec/core_functions/color/hwb/one_arg.rs | 4 - .../color/rgb/four_args/clamped.rs | 12 -- 16 files changed, 274 insertions(+), 334 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96993196..c97a32db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ project adheres to * Lots of color handling. - Spec changes for traditional css colors (PR #198). + - Made all color channels f64 instead of Rational (PR #199). * Updated sass-spec test suite to 2024-09-13. diff --git a/rsass/src/sass/functions/color/hsl.rs b/rsass/src/sass/functions/color/hsl.rs index e0dd745d..36e2c7c3 100644 --- a/rsass/src/sass/functions/color/hsl.rs +++ b/rsass/src/sass/functions/color/hsl.rs @@ -7,9 +7,8 @@ use super::{ use crate::css::{CallArgs, Value}; use crate::output::Format; use crate::sass::{ArgsError, FormalArgs, Name}; -use crate::value::{Color, Hsla, Numeric, Rational, Unit}; +use crate::value::{Color, Hsla, Numeric, Unit}; use crate::Scope; -use num_traits::{one, zero}; pub fn register(f: &mut Scope) { def_va!(f, _hsl(kwargs), |s| do_hsla(&name!(hsl), s)); @@ -32,10 +31,8 @@ pub fn register(f: &mut Scope) { Value::Color(col, _) => { let is_rgb = col.is_rgb(); let col = col.to_hsla(); - Ok( - Hsla::new(col.hue(), zero(), col.lum(), col.alpha(), !is_rgb) - .into(), - ) + Ok(Hsla::new(col.hue(), 0., col.lum(), col.alpha(), !is_rgb) + .into()) } v @ Value::Numeric(..) => Ok(Value::call("grayscale", [v])), v => Err(is_not(&v, "a color")).named(name!(color)), @@ -77,8 +74,10 @@ pub fn expose(m: &Scope, global: &mut FunctionMap) { def!(f, grayscale(color), |args| match args.get(name!(color))? { Value::Color(col, _) => { let col = col.to_hsla(); - Ok(Hsla::new(col.hue(), zero(), col.lum(), col.alpha(), false) - .into()) + Ok( + Hsla::new(col.hue(), 0., col.lum(), col.alpha(), false) + .into(), + ) } v => NumOrSpecial::try_from(v) .map_err(|e| is_not(e.value(), "a color")) @@ -94,7 +93,7 @@ pub fn expose(m: &Scope, global: &mut FunctionMap) { let col = s.get::(name!(color))?; let sat = s.get_map(name!(amount), check_amount)?; let col = col.to_hsla(); - let sat = (col.sat() + sat).clamp(zero(), one()); + let sat = (col.sat() + sat).clamp(0., 1.); Ok(Hsla::new(col.hue(), sat, col.lum(), col.alpha(), false) .into()) } @@ -186,7 +185,7 @@ fn hsla_from_values( } else { Ok(Hsla::new( check_hue(h).named(name!(hue))?, - check_pct_opt(s).named(name!(saturation))?, + f64::max(0., check_pct_opt(s).named(name!(saturation))?), check_pct_opt(l).named(name!(lightness))?, check_alpha(a).named(name!(alpha))?, true, // ?? @@ -195,13 +194,13 @@ fn hsla_from_values( } } -pub fn percentage(v: Rational) -> Value { +pub fn percentage(v: f64) -> Value { Numeric::percentage(v).into() } /// Gets a percentage as a fraction 0 .. 1. /// If v is not a percentage, keep it as it is. -fn check_pct_opt(v: Value) -> Result { +fn check_pct_opt(v: Value) -> Result { let v = Numeric::try_from(v)?; if !v.unit.is_percent() { // Note: The deprecation warning should include the parameter name @@ -214,7 +213,7 @@ fn check_pct_opt(v: Value) -> Result { v.unit ); } - Ok(v.as_ratio()? / 100) + Ok(f64::from(v.value) / 100.) } #[test] diff --git a/rsass/src/sass/functions/color/hwb.rs b/rsass/src/sass/functions/color/hwb.rs index a13955a2..2774218e 100644 --- a/rsass/src/sass/functions/color/hwb.rs +++ b/rsass/src/sass/functions/color/hwb.rs @@ -1,17 +1,14 @@ use super::super::FunctionMap; use super::hsl::percentage; use super::{ - check_alpha, check_expl_pct, eval_inner, is_not, relative_color, + check_alpha, check_expl_pct_norange, eval_inner, is_not, relative_color, CallError, CheckedArg, ResolvedArgs, }; use crate::css::{CallArgs, Value}; use crate::output::Format; use crate::sass::FormalArgs; -use crate::value::{ - Color, Hwba, ListSeparator, Numeric, Rational, Rgba, Unit, -}; +use crate::value::{Color, Hwba, ListSeparator, Numeric, Rgba, Unit}; use crate::Scope; -use num_traits::{one, zero}; pub fn register(f: &mut Scope) { def_va!(f, hwb(kwargs), hwb); @@ -57,14 +54,14 @@ fn hwb(s: &ResolvedArgs) -> Result { })? }; let hue = check_hue(hue).named(name!(hue))?; - let w = check_expl_pct(w).named(name!(whiteness))?; - let b = check_expl_pct(b).named(name!(blackness))?; + let w = check_expl_pct_norange(w).named(name!(whiteness))?; + let b = check_expl_pct_norange(b).named(name!(blackness))?; let a = check_alpha(a).named(name!(alpha))?; // I don't really agree with this, but it makes tests pass. - let hue = if w + b >= one() { zero() } else { hue }; + let hue = if w + b >= 1. { 0. } else { hue }; let hwba = Hwba::new(hue, w, b, a); let rgba = Rgba::from(&hwba); - if rgba.is_integer() { + if rgba.is_integer() && w >= 0. { Ok(rgba.into()) } else { Ok(hwba.into()) @@ -129,10 +126,10 @@ fn badchannels(v: &Value) -> CallError { )) } -fn check_hue(v: Value) -> Result { +fn check_hue(v: Value) -> Result { let vv = Numeric::try_from(v)?; if let Some(scaled) = vv.as_unit_def(Unit::Deg) { - Ok(scaled.as_ratio()?) + Ok(scaled.into()) } else { Err(is_not(&vv, "an angle")) } diff --git a/rsass/src/sass/functions/color/mod.rs b/rsass/src/sass/functions/color/mod.rs index 4a2c3b95..dc02d6c1 100644 --- a/rsass/src/sass/functions/color/mod.rs +++ b/rsass/src/sass/functions/color/mod.rs @@ -6,9 +6,9 @@ use crate::css::{CallArgs, CssString, Value}; use crate::input::SourcePos; use crate::output::Format; use crate::sass::{FormalArgs, Name}; -use crate::value::{ListSeparator, Number, Numeric, Quotes, Rational, Unit}; +use crate::value::{ListSeparator, Numeric, Quotes, Unit}; use crate::Scope; -use num_traits::{one, zero, Signed}; +use num_traits::{one, zero}; mod channels; mod hsl; mod hwb; @@ -61,7 +61,7 @@ pub fn expose(m: &Scope, global: &mut FunctionMap) { /// For the alpha parameter of rgba, hsla, hwba functions /// Special perk: Defaults to 1.0 if the value is null. -fn check_alpha(v: Value) -> Result { +fn check_alpha(v: Value) -> Result { Ok(match v { Value::Null => one(), v => { @@ -70,31 +70,29 @@ fn check_alpha(v: Value) -> Result { .ok_or_else(|| { expected_to(num, "have unit \"%\" or no units") })? - .as_ratio()? + .into() } }) } /// Get a rational number in the 0..1 range. -fn check_alpha_range(v: Value) -> Result { +fn check_alpha_range(v: Value) -> Result { let v = Numeric::try_from(v)?; - let r = v.as_ratio()?; - if r < zero() || r > one() { + if v.value < zero() || v.value > one() { Err(expected_to(v, "be within 0 and 1")) } else { - Ok(r) + Ok(v.value.into()) } } -fn check_alpha_pm(v: Value) -> Result { +fn check_alpha_pm(v: Value) -> Result { let v = Numeric::try_from(v)?; - let r = v.as_ratio()?; - if r.abs() > one() { + if v.value.abs() > one() { Err(expected_to(v, "be within -1 and 1")) } else { - Ok(r) + Ok(v.value.into()) } } -fn check_hue(v: Value) -> Result { +fn check_hue(v: Value) -> Result { let v = Numeric::try_from(v)?; let v = match v.as_unit_def(Unit::Deg) { Some(v) => v, @@ -109,13 +107,13 @@ fn check_hue(v: Value) -> Result { v.value } }; - v.as_ratio().map_err(|e| e.to_string()) + Ok(v.into()) } -fn check_pct(v: Value) -> Result { +fn check_pct(v: Value) -> Result { let val = Numeric::try_from(v)?; match val.as_unit_def(Unit::Percent) { - Some(v) => Ok(v / 100), + Some(v) => Ok(f64::from(v) / 100.), None => { dep_warn!( "Passing a number without unit % ({}) is deprecated.\ @@ -124,12 +122,20 @@ fn check_pct(v: Value) -> Result { val.format(Format::introspect()), val.unit ); - Ok(val.value / 100) + Ok(f64::from(val.value) / 100.) } } } -fn check_expl_pct(v: Value) -> Result { +fn check_expl_pct_norange(v: Value) -> Result { + let val = Numeric::try_from(v)?; + if !val.unit.is_percent() { + Err(expected_to(val, "have unit \"%\"")) + } else { + Ok(f64::from(val.value) / 100.) + } +} +fn check_expl_pct(v: Value) -> Result { let val = Numeric::try_from(v)?; if !val.unit.is_percent() { return Err(expected_to(val, "have unit \"%\"")); @@ -137,11 +143,11 @@ fn check_expl_pct(v: Value) -> Result { if val.value < zero() || val.value > 100.into() { Err(expected_to(val, "be within 0% and 100%")) } else { - Ok(val.as_ratio()? / 100) + Ok(f64::from(val.value) / 100.) } } -fn check_pct_range(v: Value) -> Result { +fn check_pct_range(v: Value) -> Result { let val = check_pct(v)?; if val < zero() || val > one() { Err(expected_to( @@ -149,44 +155,47 @@ fn check_pct_range(v: Value) -> Result { "be within 0% and 100%", )) } else { - Ok(val.as_ratio()?) + Ok(val) } } -fn check_amount(v: Value) -> Result { +fn check_amount(v: Value) -> Result { let val = check_pct(v)?; if val < zero() || val > one() { - Err(expected_to(Value::scalar(val * 100), "be within 0 and 100")) + Err(expected_to( + Value::scalar(val * 100.), + "be within 0 and 100", + )) } else { - Ok(val.as_ratio()?) + Ok(val) } } -fn check_channel(v: Value) -> Result { +fn check_channel(v: Value) -> Result { num2chan(&Numeric::try_from(v)?) } -fn check_channel_range(v: Value) -> Result { +fn check_channel_range(v: Value) -> Result { let v = Numeric::try_from(v)?; let r = num2chan(&v)?; - if r > Rational::from_integer(255) || r < zero() { + if r > 255. || r < zero() { Err(expected_to(v, "be within 0 and 255")) } else { Ok(r) } } -fn check_channel_pm(v: Value) -> Result { +fn check_channel_pm(v: Value) -> Result { let v = Numeric::try_from(v)?; let r = num2chan(&v)?; - if r.abs() > Rational::from_integer(255) { + if r.abs() > 255. { Err(expected_to(v, "be within -255 and 255")) } else { Ok(r) } } -fn num2chan(v: &Numeric) -> Result { - let r = v.as_ratio()?; +fn num2chan(v: &Numeric) -> Result { + let r = f64::from(v.value.clone()); if v.unit.is_percent() { - Ok(r * 255 / 100) + Ok(r * 255. / 100.) } else { Ok(r) } diff --git a/rsass/src/sass/functions/color/other.rs b/rsass/src/sass/functions/color/other.rs index d4a7064b..57b61743 100644 --- a/rsass/src/sass/functions/color/other.rs +++ b/rsass/src/sass/functions/color/other.rs @@ -1,16 +1,15 @@ use super::{ check_alpha_pm, check_alpha_range, check_channel_pm, check_channel_range, - check_expl_pct, check_hue, expected_to, CallError, CheckedArg, - FunctionMap, Name, + check_expl_pct, check_hue, check_pct, check_pct_range, expected_to, + CallError, CheckedArg, FunctionMap, Name, }; use crate::css::{CallArgs, Value}; -use crate::value::{Color, Hsla, Hwba, Numeric, Rational, RgbFormat, Rgba}; +use crate::value::{Color, Hsla, Hwba, Numeric, RgbFormat, Rgba}; use crate::Scope; -use num_traits::{one, zero, Signed}; pub fn register(f: &mut Scope) { def_va!(f, adjust(color, kwargs), |s| { - fn opt_add(a: Rational, b: Option) -> Rational { + fn opt_add(a: f64, b: Option) -> f64 { if let Some(b) = b { a + b } else { @@ -66,10 +65,7 @@ pub fn register(f: &mut Scope) { sat, lum, opt_add(hsla.alpha(), a_adj), - hsla.hsla_format - || sat > one() - || lum > one() - || lum < zero(), + hsla.hsla_format || sat > 1. || lum > 1. || lum < 0., ) .into()) } else { @@ -80,19 +76,18 @@ pub fn register(f: &mut Scope) { } }); def_va!(f, scale(color, kwargs), |s| { - let cmb = |orig: Rational, x: Option, max: Rational| match x - { + let cmb = |orig: f64, x: Option, max: f64| match x { None => orig, Some(x) => { - if x.is_positive() { + if x.is_sign_positive() { orig + (max - orig) * x } else { orig + orig * x } } }; - let one: Rational = one(); - let ff = Rational::from_integer(255); + let one = 1.0; + let ff = 255.0; let color: Color = s.get(name!(color))?; let mut args = s.get_map(name!(kwargs), CallArgs::from_value)?; @@ -188,9 +183,8 @@ pub fn register(f: &mut Scope) { return Ok(rgba.into()); } let hue = take_opt(&mut args, name!(hue), check_hue)?; - let sat = - take_opt(&mut args, name!(saturation), check_pct_opt_range)?; - let lig = take_opt(&mut args, name!(lightness), check_pct_opt_range)?; + let sat = take_opt(&mut args, name!(saturation), check_pct_range)?; + let lig = take_opt(&mut args, name!(lightness), check_pct_range)?; if sat.is_some() || lig.is_some() { no_more_in_space(&args, "hsl")?; } @@ -294,27 +288,15 @@ where args.named.remove(&name).map(check).transpose().named(name) } -fn check_pct(v: Value) -> Result { - Ok(Numeric::try_from(v)?.as_ratio()? / 100) -} -fn check_pct_expl_pm(v: Value) -> Result { +fn check_pct_expl_pm(v: Value) -> Result { let val = Numeric::try_from(v)?; if !val.unit.is_percent() { return Err(expected_to(val, "have unit \"%\"")); } - if val.value.abs() > 100.into() { + if f64::from(val.value.abs()) > 100. { Err(expected_to(val, "be within -100% and 100%")) } else { - Ok(val.as_ratio()? / 100) - } -} - -fn check_pct_opt_range(v: Value) -> Result { - let val = Numeric::try_from(v)?; - if val.value < zero() || val.value > 100.into() { - Err(expected_to(val, "be within 0% and 100%")) - } else { - Ok(val.as_ratio()? / 100) + Ok(f64::from(val.value) / 100.) } } diff --git a/rsass/src/sass/functions/color/rgb.rs b/rsass/src/sass/functions/color/rgb.rs index b539f150..bbd3f543 100644 --- a/rsass/src/sass/functions/color/rgb.rs +++ b/rsass/src/sass/functions/color/rgb.rs @@ -6,9 +6,8 @@ use super::{ }; use crate::css::{CallArgs, Value}; use crate::sass::{ArgsError, FormalArgs, Name}; -use crate::value::{Color, Rational, RgbFormat, Rgba}; +use crate::value::{Color, RgbFormat, Rgba}; use crate::Scope; -use num_traits::{one, Zero}; pub fn register(f: &mut Scope) { def_va!(f, _rgb(kwargs), |s| do_rgba(&name!(rgb), s)); @@ -31,26 +30,25 @@ pub fn register(f: &mut Scope) { let b: Color = s.get(name!(color2))?; let b = b.to_rgba(); let w = s.get_map(name!(weight), check_pct_range)?; - let one: Rational = one(); let w_a = { let wa = a.alpha() - b.alpha(); - let w2 = w * 2 - 1; - let divis = w2 * wa + 1; - if divis.is_zero() { + let w2 = w * 2. - 1.; + let divis = w2 * wa + 1.; + if divis == 0. { w } else { - (((w2 + wa) / divis) + 1) / 2 + (((w2 + wa) / divis) + 1.) / 2. } }; - let w_b = one - w_a; + let w_b = 1. - w_a; let m_c = |c_a, c_b| w_a * c_a + w_b * c_b; Ok(Rgba::new( m_c(a.red(), b.red()), m_c(a.green(), b.green()), m_c(a.blue(), b.blue()), - a.alpha() * w + b.alpha() * (one - w), + a.alpha() * w + b.alpha() * (1. - w), RgbFormat::Name, ) .into()) @@ -63,7 +61,7 @@ pub fn register(f: &mut Scope) { } col => { let w = s.get_map(name!(weight), check_pct_range)?; - if w == one() { + if w == 1. { match col { v @ Value::Numeric(..) => { Ok(Value::call("invert", [v])) @@ -98,7 +96,7 @@ pub fn expose(m: &Scope, global: &mut FunctionMap) { } col => { let w = s.get_map(name!(weight), check_pct_range)?; - if w == one() { + if w == 1. { NumOrSpecial::try_from(col) .map_err(|e| is_not(e.value(), "a color")) .named(name!(color)) diff --git a/rsass/src/value/colors/convert.rs b/rsass/src/value/colors/convert.rs index a6cb3e60..a91ae10c 100644 --- a/rsass/src/value/colors/convert.rs +++ b/rsass/src/value/colors/convert.rs @@ -1,34 +1,34 @@ -use super::*; +use super::{Hsla, Hwba, RgbFormat, Rgba}; impl From<&Hsla> for Rgba { fn from(hsla: &Hsla) -> Self { - let hue = hsla.hue() / 360; + let hue = hsla.hue() / 360.; let sat = hsla.sat(); let lum = hsla.lum(); - if sat.is_zero() { - let gray = lum * 255; + if sat == 0. { + let gray = lum * 255.; Self::new(gray, gray, gray, hsla.alpha(), RgbFormat::Name) } else { - fn hue2rgb(p: Rational, q: Rational, t: Rational) -> Rational { - let t = (t - t.floor()) * 6; - match t.to_integer() { + fn hue2rgb(p: f64, q: f64, t: f64) -> f64 { + let t = (t - t.floor()) * 6.; + match t as u8 { 0 => p + (q - p) * t, 1 | 2 => q, - 3 => p + (p - q) * (t - 4), + 3 => p + (p - q) * (t - 4.), _ => p, } } - let q = if lum < Rational::new(1, 2) { - lum * (sat + 1) + let q = if lum < 0.5 { + lum * (sat + 1.) } else { lum + sat - lum * sat }; - let p = lum * 2 - q; - + let p = lum * 2. - q; + const THIRD: f64 = 1. / 3.; Self::new( - hue2rgb(p, q, hue + Rational::new(1, 3)) * 255, - hue2rgb(p, q, hue) * 255, - hue2rgb(p, q, hue - Rational::new(1, 3)) * 255, + hue2rgb(p, q, hue + THIRD) * 255., + hue2rgb(p, q, hue) * 255., + hue2rgb(p, q, hue - THIRD) * 255., hsla.alpha(), RgbFormat::Name, ) @@ -46,34 +46,39 @@ impl From<&Hwba> for Hsla { fn from(hwba: &Hwba) -> Self { let w = hwba.whiteness(); let b = hwba.blackness(); - let l = (Rational::one() - b + w) / 2; - let s = if l.is_zero() || l.is_one() { - zero() + let l = (1. - b + w) / 2.; + let s = if l == 0. || l == 1. { + 0. + } else { + (1. - b - l) / f64::min(l, 1. - l) + }; + let (hue, lum) = if w.is_finite() && b.is_finite() { + (hwba.hue(), l) } else { - (Rational::one() - b - l) / std::cmp::min(l, Rational::one() - l) + (f64::NAN, f64::NAN) }; - Self::new(hwba.hue(), s, l, hwba.alpha(), false) + Self::new(hue, s, lum, hwba.alpha(), false) } } impl From<&Rgba> for Hsla { fn from(rgba: &Rgba) -> Self { let (red, green, blue) = - (rgba.red() / 255, rgba.green() / 255, rgba.blue() / 255); + (rgba.red() / 255., rgba.green() / 255., rgba.blue() / 255.); let (max, min, largest) = max_min_largest(red, green, blue); if max == min { - Self::new(zero(), zero(), max, rgba.alpha(), false) + Self::new(0., 0., max, rgba.alpha(), false) } else { let d = max - min; let hue = match largest { - 0 => (green - blue) / d + if green < blue { 6 } else { 0 }, - 1 => (blue - red) / d + 2, - _ => (red - green) / d + 4, - } * (360 / 6); + 0 => (green - blue) / d + if green < blue { 6. } else { 0. }, + 1 => (blue - red) / d + 2., + _ => (red - green) / d + 4., + } * (360. / 6.); let mm = max + min; - let sat = d / if mm > one() { -mm + 2 } else { mm }; - Self::new(hue, sat, mm / 2, rgba.alpha(), false) + let sat = d / if mm > 1. { -mm + 2. } else { mm }; + Self::new(hue, sat, mm / 2., rgba.alpha(), false) } } } @@ -81,11 +86,10 @@ impl From<&Rgba> for Hsla { impl From<&Rgba> for Hwba { fn from(rgba: &Rgba) -> Self { let hsla = Hsla::from(rgba); - let arr = [rgba.red(), rgba.blue(), rgba.green()]; Self::new( hsla.hue(), - *arr.iter().min().unwrap() / 255, - Rational::one() - *arr.iter().max().unwrap() / 255, + rgba.red().min(rgba.blue()).min(rgba.green()) / 255., + 1. - rgba.red().max(rgba.blue()).max(rgba.green()) / 255., hsla.alpha(), ) } @@ -93,24 +97,24 @@ impl From<&Rgba> for Hwba { impl From<&Hsla> for Hwba { fn from(hsla: &Hsla) -> Self { let rgba = Rgba::from(hsla); - let arr = [rgba.red(), rgba.blue(), rgba.green()]; Self::new( hsla.hue(), - Rational::one() - *arr.iter().max().unwrap() / 255, - *arr.iter().min().unwrap() / 255, + rgba.red().min(rgba.blue()).min(rgba.green()) / 255., + 1. - rgba.red().max(rgba.blue()).max(rgba.green()) / 255., hsla.alpha(), ) } } // Find which of three numbers are largest and smallest -fn max_min_largest( - a: Rational, - b: Rational, - c: Rational, -) -> (Rational, Rational, u32) { - let v = [(a, 0), (b, 1), (c, 2)]; - let max = v.iter().max().unwrap(); - let min = v.iter().min().unwrap(); - (max.0, min.0, max.1) +fn max_min_largest(a: f64, b: f64, c: f64) -> (f64, f64, u32) { + let (max, largest) = if a > b && a > c { + (a, 0) + } else if b > a && b > c { + (b, 1) + } else { + (c, 2) + }; + let min = a.min(b).min(c); + (max, min, largest) } diff --git a/rsass/src/value/colors/hsla.rs b/rsass/src/value/colors/hsla.rs index 70a9e762..55bed948 100644 --- a/rsass/src/value/colors/hsla.rs +++ b/rsass/src/value/colors/hsla.rs @@ -1,67 +1,66 @@ +use crate::css::Value; use crate::output::{Format, Formatted}; -use crate::value::{Number, Rational}; -use num_traits::{one, zero, One as _, Signed}; +use crate::value::{Number, Numeric}; use std::fmt::{self, Display}; /// A color defined by hue, saturation, luminance, and alpha. -#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[derive(Clone, Debug, PartialEq, PartialOrd)] pub struct Hsla { - hue: Rational, - sat: Rational, - lum: Rational, - alpha: Rational, + hue: f64, + sat: f64, + lum: f64, + alpha: f64, pub(crate) hsla_format: bool, } impl Hsla { /// Create a new hsla color. pub fn new( - hue: Rational, - sat: Rational, - lum: Rational, - alpha: Rational, + hue: f64, + sat: f64, + lum: f64, + alpha: f64, hsla_format: bool, ) -> Self { Self { hue: deg_mod(hue), - sat: sat.max(zero()), + sat: sat.clamp(0., f64::INFINITY), lum, - alpha: alpha.clamp(zero(), one()), + alpha: alpha.max(0.).min(1.), hsla_format, } } /// Get the hue of this color. - pub fn hue(&self) -> Rational { + pub fn hue(&self) -> f64 { self.hue } /// Get the saturation of this color. - pub fn sat(&self) -> Rational { + pub fn sat(&self) -> f64 { self.sat } /// Get the lumination of this color. - pub fn lum(&self) -> Rational { + pub fn lum(&self) -> f64 { self.lum } /// Get the alpha value of this color. /// /// Zero is fully transparent, one is fully opaque. - pub fn alpha(&self) -> Rational { + pub fn alpha(&self) -> f64 { self.alpha } /// Set the alpha value of this color. /// /// Zero is fully transparent, one is fully opaque. - pub fn set_alpha(&mut self, alpha: Rational) { - self.alpha = alpha.clamp(zero(), one()); + pub fn set_alpha(&mut self, alpha: f64) { + self.alpha = alpha.clamp(0., 1.); } - pub(crate) fn invert(&self, weight: Rational) -> Self { - let one = Rational::one(); + pub(crate) fn invert(&self, weight: f64) -> Self { Self { - hue: deg_mod(self.hue + 180), + hue: deg_mod(self.hue + 180.), sat: self.sat, - lum: (one - self.lum) * weight + self.lum * (one - weight), + lum: (1. - self.lum) * weight + self.lum * (1. - weight), alpha: self.alpha, hsla_format: self.hsla_format, } @@ -81,10 +80,10 @@ impl Hsla { } /// Value is an angle in degrees, return same angle, but 0 <= value < 360.x -fn deg_mod(value: Rational) -> Rational { - let turn = Rational::from_integer(360); +fn deg_mod(value: f64) -> f64 { + let turn = 360.; let value = value % turn; - if value.is_negative() { + if value.is_sign_negative() { value + turn } else { value @@ -94,26 +93,28 @@ fn deg_mod(value: Rational) -> Rational { 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); + // Special: Don't round the hue to 360! + let hue = if hsla.hue + 1e-7 > 360. { 0. } else { hsla.hue }; + let hue = Value::scalar(hue); + let sat = Value::from(Numeric::percentage(hsla.sat)); + let lum = Value::from(Numeric::percentage(hsla.lum)); let a = hsla.alpha; - if a >= one() { + if a >= 1. { write!( out, - "hsl({}, {}%, {}%)", - hue.format(self.format), - sat.format(self.format), - lum.format(self.format), + "hsl({}, {}, {})", + hue.to_string(self.format), + sat.to_string(self.format), + lum.to_string(self.format), ) } else { let a = Number::from(a); write!( out, - "hsla({}, {}%, {}%, {})", - hue.format(self.format), - sat.format(self.format), - lum.format(self.format), + "hsla({}, {}, {}, {})", + hue.to_string(self.format), + sat.to_string(self.format), + lum.to_string(self.format), a.format(self.format) ) } diff --git a/rsass/src/value/colors/hwba.rs b/rsass/src/value/colors/hwba.rs index 17f35da5..d76aced0 100644 --- a/rsass/src/value/colors/hwba.rs +++ b/rsass/src/value/colors/hwba.rs @@ -1,6 +1,3 @@ -use super::Rational; -use num_traits::{one, zero}; - /// A color defined by hue, whiteness, blackness, and alpha. /// /// All components are rational numbers. @@ -8,12 +5,12 @@ use num_traits::{one, zero}; /// The whiteness, blackness, and alpha are all in the zero to one /// range (inclusive), whith the additional invariant that whiteness + /// blackness will never be more than one. -#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[derive(Clone, Debug, PartialEq, PartialOrd)] pub struct Hwba { - hue: Rational, - w: Rational, - b: Rational, - alpha: Rational, + hue: f64, + w: f64, + b: f64, + alpha: f64, } impl Hwba { @@ -21,16 +18,11 @@ impl Hwba { /// /// Hue is modulo 360 degrees. Other inputs will be clamped to /// their ranges. - pub fn new( - hue: Rational, - w: Rational, - b: Rational, - alpha: Rational, - ) -> Self { - let mut w = w.clamp(zero(), one()); - let mut b = b.clamp(zero(), one()); + pub fn new(hue: f64, w: f64, b: f64, alpha: f64) -> Self { + let mut w = w; + let mut b = b; let wbsum = w + b; - if w + b > one() { + if !(wbsum < 1.) { w /= wbsum; b /= wbsum; } @@ -38,36 +30,36 @@ impl Hwba { hue, w, b, - alpha: alpha.clamp(zero(), one()), + alpha: alpha.clamp(0., 1.), } } /// Get the hue of this color. - pub fn hue(&self) -> Rational { + pub fn hue(&self) -> f64 { self.hue } /// Get the whiteness of this color. /// /// Zero is no whiteness, one means this color is white. - pub fn whiteness(&self) -> Rational { + pub fn whiteness(&self) -> f64 { self.w } /// Get the black of this color. /// /// Zero is no blackness, one means this color is black. - pub fn blackness(&self) -> Rational { + pub fn blackness(&self) -> f64 { self.b } /// Get the alpha value of this color. /// /// Zero is fully transparent, one is fully opaque. - pub fn alpha(&self) -> Rational { + pub fn alpha(&self) -> f64 { self.alpha } /// Set the alpha value of this color. /// /// Zero is fully transparent, one is fully opaque. - pub fn set_alpha(&mut self, alpha: Rational) { - self.alpha = alpha.clamp(zero(), one()); + pub fn set_alpha(&mut self, alpha: f64) { + self.alpha = alpha.clamp(0., 1.); } } diff --git a/rsass/src/value/colors/mod.rs b/rsass/src/value/colors/mod.rs index fbd33653..42f94e0a 100644 --- a/rsass/src/value/colors/mod.rs +++ b/rsass/src/value/colors/mod.rs @@ -7,14 +7,12 @@ mod rgba; pub use self::hsla::Hsla; pub use self::hwba::Hwba; pub use self::rgba::{RgbFormat, Rgba}; -use super::Rational; use crate::output::{Format, Formatted}; -use num_traits::{one, zero, One, Zero}; use std::borrow::Cow; use std::fmt::{self, Display}; /// A color in sass/css. May be a Rgba, Hsla, or Hwba value. -#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Clone, Debug, PartialEq)] pub enum Color { /// A rgba color, defined by red, green, blue and alpha components. Rgba(Rgba), @@ -24,6 +22,27 @@ pub enum Color { Hwba(Hwba), } +impl Eq for Color {} +impl Ord for Color { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + match (self, other) { + (Color::Hsla(a), Color::Hsla(b)) => a.partial_cmp(b).unwrap(), + (Color::Hsla(a), Color::Hwba(b)) => { + a.partial_cmp(&Hsla::from(b)).unwrap() + } + (Color::Hwba(a), Color::Hsla(b)) => { + Hsla::from(a).partial_cmp(b).unwrap() + } + (a, b) => a.to_rgba().cmp(&b.to_rgba()), + } + } +} +impl PartialOrd for Color { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + impl Color { pub(crate) fn is_rgb(&self) -> bool { matches!(self, Self::Rgba(_)) @@ -66,7 +85,7 @@ impl Color { /// Get the alpha channel of this color. /// /// The alpha channel is a rational value between 0 and 1. - pub fn get_alpha(&self) -> Rational { + pub fn get_alpha(&self) -> f64 { match self { Self::Rgba(rgba) => rgba.alpha(), Self::Hsla(hsla) => hsla.alpha(), @@ -76,8 +95,8 @@ impl Color { /// Set the alpha channel of this color. /// /// The alpha channel is a rational value between 0 and 1. - pub fn set_alpha(&mut self, alpha: Rational) { - let alpha = alpha.clamp(zero(), one()); + pub fn set_alpha(&mut self, alpha: f64) { + let alpha = alpha.clamp(0., 1.); match self { Self::Rgba(ref mut rgba) => rgba.set_alpha(alpha), Self::Hsla(ref mut hsla) => hsla.set_alpha(alpha), @@ -85,7 +104,7 @@ impl Color { } } /// Rotate the hue of this color by a specific number of degrees. - pub fn rotate_hue(&self, val: Rational) -> Self { + pub fn rotate_hue(&self, val: f64) -> Self { match self { Self::Rgba(rgba) => { let hsla = Hsla::from(rgba); @@ -115,7 +134,7 @@ impl Color { .into(), } } - pub(crate) fn invert(&self, weight: Rational) -> Self { + pub(crate) fn invert(&self, weight: f64) -> Self { match self { Color::Rgba(rgba) => rgba.invert(weight).into(), Color::Hsla(hsla) => hsla.invert(weight).into(), diff --git a/rsass/src/value/colors/rgba.rs b/rsass/src/value/colors/rgba.rs index fd7bd3d0..a4cf7d10 100644 --- a/rsass/src/value/colors/rgba.rs +++ b/rsass/src/value/colors/rgba.rs @@ -1,10 +1,8 @@ //! Color names from #![allow(clippy::unreadable_literal)] -use super::Rational; use crate::output::{Format, Formatted}; use crate::value::Number; use lazy_static::lazy_static; -use num_traits::{one, zero, One, Signed, Zero}; use std::cmp::Ordering; use std::collections::BTreeMap; use std::fmt::{self, Display}; @@ -12,10 +10,10 @@ use std::fmt::{self, Display}; /// A color defined by red, green, blue, and alpha components. #[derive(Clone, Debug)] pub struct Rgba { - red: Rational, - green: Rational, - blue: Rational, - alpha: Rational, + red: f64, + green: f64, + blue: f64, + alpha: f64, source: RgbFormat, } @@ -34,46 +32,39 @@ pub enum RgbFormat { impl Rgba { /// Create a new rgba color. - pub fn new( - r: Rational, - g: Rational, - b: Rational, - a: Rational, - s: RgbFormat, - ) -> Self { - let ff = Rational::new(255, 1); - let one = Rational::one(); + pub fn new(r: f64, g: f64, b: f64, a: f64, s: RgbFormat) -> Self { + let ff = 255.; Self { - red: cap(r, &ff), - green: cap(g, &ff), - blue: cap(b, &ff), - alpha: cap(a, &one), + red: cap(r, ff), + green: cap(g, ff), + blue: cap(b, ff), + alpha: cap(a, 1.), source: s, } } /// Create a color from rgb byte values. pub fn from_rgb(r: u8, g: u8, b: u8) -> Self { Self { - red: Rational::from_integer(r.into()), - green: Rational::from_integer(g.into()), - blue: Rational::from_integer(b.into()), - alpha: Rational::one(), + red: r.into(), + green: g.into(), + blue: b.into(), + alpha: 1.0, source: RgbFormat::LongHex, } } /// Create a color from rgba byte values. pub fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Self { Self { - red: Rational::from_integer(r.into()), - green: Rational::from_integer(g.into()), - blue: Rational::from_integer(b.into()), - alpha: Rational::from_integer(a.into()) / 255, + red: r.into(), + green: g.into(), + blue: b.into(), + alpha: f64::from(a) / 255., source: RgbFormat::LongHex, } } fn is_opaque(&self) -> bool { - self.alpha >= one() + self.alpha >= 1. } /// If this color is equal to a named color, get the name. pub fn name(&self) -> Option<&'static str> { @@ -86,46 +77,37 @@ impl Rgba { let name = name.to_lowercase(); let name: &str = &name; if name == "transparent" { - return Some(Self::new( - zero(), - zero(), - zero(), - zero(), - RgbFormat::Name, - )); + return Some(Self::new(0., 0., 0., 0., RgbFormat::Name)); } LOOKUP.n2v.get(name).map(|n| { let [_, r, g, b] = n.to_be_bytes(); - Self::new( - i64::from(r).into(), - i64::from(g).into(), - i64::from(b).into(), - one(), - RgbFormat::Name, - ) + Self::new(r.into(), g.into(), b.into(), 1., RgbFormat::Name) }) } /// Return true if all chanels are zero. pub fn all_zero(&self) -> bool { - self.alpha.is_zero() - && self.red.is_zero() - && self.green.is_zero() - && self.blue.is_zero() + self.alpha == 0. + && self.red == 0. + && self.green == 0. + && self.blue == 0. } pub(crate) fn is_integer(&self) -> bool { - self.red.is_integer() - && self.green.is_integer() - && self.blue.is_integer() + near_integer(self.red) + && near_integer(self.green) + && near_integer(self.blue) && self.is_opaque() } /// Get a (r, g, b, a) byte-value tuple for this color. pub fn to_bytes(&self) -> (u8, u8, u8, u8) { - fn byte(v: Rational) -> u8 { - v.round().to_integer() as u8 + fn byte(v: f64) -> u8 { + v.round() as u8 } - let a = self.alpha * 255; - (byte(self.red), byte(self.green), byte(self.blue), byte(a)) + fn fb(v: f64) -> u8 { + v.round() as u8 + } + let a = self.alpha * 255.; + (byte(self.red), byte(self.green), byte(self.blue), fb(a)) } /// Get a (r, g, b) byte-value tuple for this color. /// @@ -135,9 +117,9 @@ impl Rgba { if !self.is_opaque() { return None; } - fn byte(v: Rational) -> Option { - if v.is_integer() { - Some(v.round().to_integer() as u8) + fn byte(v: f64) -> Option { + if (v.round() - v).abs() < 1e-7 { + Some(v.round() as u8) } else { None } @@ -151,32 +133,32 @@ impl Rgba { } } /// Get the red component. - pub fn red(&self) -> Rational { + pub fn red(&self) -> f64 { self.red } /// Get the green component. - pub fn green(&self) -> Rational { + pub fn green(&self) -> f64 { self.green } /// Get the blue component. - pub fn blue(&self) -> Rational { + pub fn blue(&self) -> f64 { self.blue } /// Get the alpha value of this color. /// /// Zero is fully transparent, one is fully opaque. - pub fn alpha(&self) -> Rational { + pub fn alpha(&self) -> f64 { self.alpha } /// Set the alpha value of this color. /// /// Zero is fully transparent, one is fully opaque. - pub fn set_alpha(&mut self, alpha: Rational) { - self.alpha = cap(alpha, &one()); + pub fn set_alpha(&mut self, alpha: f64) { + self.alpha = alpha.clamp(0., 1.); } - pub(crate) fn invert(&self, weight: Rational) -> Self { - let inv = |v: Rational| -(v - 255) * weight + v * -(weight - 1); + pub(crate) fn invert(&self, weight: f64) -> Self { + let inv = |v: f64| -(v - 255.) * weight + v * (1. - weight); Rgba::new( inv(self.red()), inv(self.green()), @@ -216,10 +198,11 @@ impl Ord for Rgba { fn cmp(&self, other: &Self) -> Ordering { // ignores source! self.red - .cmp(&other.red) - .then_with(|| self.green.cmp(&other.green)) - .then_with(|| self.blue.cmp(&other.blue)) - .then_with(|| self.alpha.cmp(&other.alpha)) + .partial_cmp(&other.red) + .unwrap() + .then_with(|| self.green.partial_cmp(&other.green).unwrap()) + .then_with(|| self.blue.partial_cmp(&other.blue).unwrap()) + .then_with(|| self.alpha.partial_cmp(&other.alpha).unwrap()) } } impl PartialOrd for Rgba { @@ -228,14 +211,8 @@ impl PartialOrd for Rgba { } } -fn cap(n: Rational, max: &Rational) -> Rational { - if n > *max { - *max - } else if n.is_negative() { - Rational::zero() - } else { - n - } +fn cap(n: f64, max: f64) -> f64 { + f64::min(f64::max(0., n), max) } #[test] @@ -508,3 +485,7 @@ fn write_rgba( } } } + +fn near_integer(v: f64) -> bool { + (v - v.round()).abs() < 1e-7 +} diff --git a/rsass/tests/spec/core_functions/color/adjust/hwb.rs b/rsass/tests/spec/core_functions/color/adjust/hwb.rs index bfdb26b4..5fcde0b7 100644 --- a/rsass/tests/spec/core_functions/color/adjust/hwb.rs +++ b/rsass/tests/spec/core_functions/color/adjust/hwb.rs @@ -90,7 +90,6 @@ mod blackness { ); } #[test] - #[ignore] // wrong result fn max() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -179,7 +178,6 @@ mod whiteness { ); } #[test] - #[ignore] // wrong result fn max() { assert_eq!( runner().ok("@use \"sass:color\";\ diff --git a/rsass/tests/spec/core_functions/color/hsl/four_args/out_of_gamut.rs b/rsass/tests/spec/core_functions/color/hsl/four_args/out_of_gamut.rs index 90f3e92f..3c18740a 100644 --- a/rsass/tests/spec/core_functions/color/hsl/four_args/out_of_gamut.rs +++ b/rsass/tests/spec/core_functions/color/hsl/four_args/out_of_gamut.rs @@ -14,7 +14,6 @@ mod alpha { use super::runner; #[test] - #[ignore] // unexepected error fn nan() { assert_eq!( runner().ok("a {b: hsl(0, 100%, 50%, calc(NaN))}\n"), @@ -24,7 +23,6 @@ mod alpha { ); } #[test] - #[ignore] // unexepected error fn negative_infinity() { assert_eq!( runner().ok("a {b: hsl(0, 100%, 50%, calc(-infinity))}\n"), @@ -34,7 +32,6 @@ mod alpha { ); } #[test] - #[ignore] // unexepected error fn positive_infinity() { assert_eq!( runner().ok("a {b: hsl(0, 100%, 50%, calc(infinity))}\n"), @@ -77,7 +74,6 @@ mod hue { use super::runner; #[test] - #[ignore] // unexepected error fn nan() { assert_eq!( runner().ok("a {b: hsl(calc(NaN), 100%, 50%)}\n"), @@ -87,7 +83,6 @@ mod hue { ); } #[test] - #[ignore] // unexepected error fn negative_infinity() { assert_eq!( runner().ok("a {b: hsl(calc(-infinity), 100%, 50%)}\n"), @@ -97,7 +92,6 @@ mod hue { ); } #[test] - #[ignore] // unexepected error fn positive_infinity() { assert_eq!( runner().ok("a {b: hsl(calc(infinity), 100%, 50%)}\n"), @@ -117,7 +111,6 @@ mod lightness { use super::runner; #[test] - #[ignore] // unexepected error fn nan() { assert_eq!( runner().ok("a {b: hsl(0, 100%, calc(NaN))}\n"), @@ -127,7 +120,6 @@ mod lightness { ); } #[test] - #[ignore] // unexepected error fn negative_infinity() { assert_eq!( runner().ok("a {b: hsl(0, 100%, calc(-infinity))}\n"), @@ -137,7 +129,6 @@ mod lightness { ); } #[test] - #[ignore] // unexepected error fn positive_infinity() { assert_eq!( runner().ok("a {b: hsl(0, 100%, calc(infinity))}\n"), @@ -166,7 +157,6 @@ mod saturation { use super::runner; #[test] - #[ignore] // unexepected error fn nan() { assert_eq!( runner().ok("a {b: hsl(0, calc(NaN), 50%)}\n"), @@ -176,7 +166,6 @@ mod saturation { ); } #[test] - #[ignore] // unexepected error fn negative_infinity() { assert_eq!( runner().ok("a {b: hsl(0, calc(-infinity), 50%)}\n"), @@ -186,7 +175,6 @@ mod saturation { ); } #[test] - #[ignore] // unexepected error fn positive_infinity() { assert_eq!( runner().ok("a {b: hsl(0, calc(infinity), 50%)}\n"), diff --git a/rsass/tests/spec/core_functions/color/hwb/four_args.rs b/rsass/tests/spec/core_functions/color/hwb/four_args.rs index 189594c4..76e95793 100644 --- a/rsass/tests/spec/core_functions/color/hwb/four_args.rs +++ b/rsass/tests/spec/core_functions/color/hwb/four_args.rs @@ -14,7 +14,6 @@ mod alpha { use super::runner; #[test] - #[ignore] // unexepected error fn nan() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -25,7 +24,6 @@ mod alpha { ); } #[test] - #[ignore] // unexepected error fn negative_infinity() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -36,7 +34,6 @@ mod alpha { ); } #[test] - #[ignore] // unexepected error fn positive_infinity() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -174,7 +171,6 @@ mod blackness { use super::runner; #[test] - #[ignore] // unexepected error fn above_max() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -185,7 +181,6 @@ mod blackness { ); } #[test] - #[ignore] // unexepected error fn below_min() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -200,7 +195,6 @@ mod blackness { use super::runner; #[test] - #[ignore] // unexepected error fn nan() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -211,7 +205,6 @@ mod blackness { ); } #[test] - #[ignore] // unexepected error fn negative_infinity() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -222,7 +215,6 @@ mod blackness { ); } #[test] - #[ignore] // unexepected error fn positive_infinity() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -254,7 +246,7 @@ mod hue { use super::runner; #[test] - #[ignore] // unexepected error + #[ignore] // wrong result fn nan() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -265,7 +257,7 @@ mod hue { ); } #[test] - #[ignore] // unexepected error + #[ignore] // wrong result fn negative_infinity() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -276,7 +268,7 @@ mod hue { ); } #[test] - #[ignore] // unexepected error + #[ignore] // wrong result fn positive_infinity() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -316,7 +308,6 @@ mod whiteness { use super::runner; #[test] - #[ignore] // unexepected error fn above_max() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -327,7 +318,6 @@ mod whiteness { ); } #[test] - #[ignore] // unexepected error fn below_min() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -342,7 +332,6 @@ mod whiteness { use super::runner; #[test] - #[ignore] // unexepected error fn nan() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -353,7 +342,6 @@ mod whiteness { ); } #[test] - #[ignore] // unexepected error fn negative_infinity() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -364,7 +352,6 @@ mod whiteness { ); } #[test] - #[ignore] // unexepected error fn positive_infinity() { assert_eq!( runner().ok("@use \"sass:color\";\ diff --git a/rsass/tests/spec/core_functions/color/hwb/one_arg.rs b/rsass/tests/spec/core_functions/color/hwb/one_arg.rs index d9174252..8a157e71 100644 --- a/rsass/tests/spec/core_functions/color/hwb/one_arg.rs +++ b/rsass/tests/spec/core_functions/color/hwb/one_arg.rs @@ -109,7 +109,6 @@ mod blackness { use super::runner; #[test] - #[ignore] // unexepected error fn above_max() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -120,7 +119,6 @@ mod blackness { ); } #[test] - #[ignore] // unexepected error fn below_min() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -382,7 +380,6 @@ mod whiteness { use super::runner; #[test] - #[ignore] // unexepected error fn above_max() { assert_eq!( runner().ok("@use \"sass:color\";\ @@ -393,7 +390,6 @@ mod whiteness { ); } #[test] - #[ignore] // unexepected error fn below_min() { assert_eq!( runner().ok("@use \"sass:color\";\ diff --git a/rsass/tests/spec/core_functions/color/rgb/four_args/clamped.rs b/rsass/tests/spec/core_functions/color/rgb/four_args/clamped.rs index d19d382c..559087fe 100644 --- a/rsass/tests/spec/core_functions/color/rgb/four_args/clamped.rs +++ b/rsass/tests/spec/core_functions/color/rgb/four_args/clamped.rs @@ -32,7 +32,6 @@ mod alpha { use super::runner; #[test] - #[ignore] // unexepected error fn nan() { assert_eq!( runner().ok("a {b: rgb(0, 0, 0, calc(NaN))}\n"), @@ -42,7 +41,6 @@ mod alpha { ); } #[test] - #[ignore] // unexepected error fn negative_infinity() { assert_eq!( runner().ok("a {b: rgb(0, 0, 0, calc(-infinity))}\n"), @@ -52,7 +50,6 @@ mod alpha { ); } #[test] - #[ignore] // unexepected error fn positive_infinity() { assert_eq!( runner().ok("a {b: rgb(0, 0, 0, calc(infinity))}\n"), @@ -72,7 +69,6 @@ mod blue { use super::runner; #[test] - #[ignore] // unexepected error fn nan() { assert_eq!( runner().ok("a {b: rgb(0, 0, calc(NaN), 0.5)}\n"), @@ -82,7 +78,6 @@ mod blue { ); } #[test] - #[ignore] // unexepected error fn negative_infinity() { assert_eq!( runner().ok("a {b: rgb(0, 0, calc(-infinity), 0.5)}\n"), @@ -92,7 +87,6 @@ mod blue { ); } #[test] - #[ignore] // unexepected error fn positive_infinity() { assert_eq!( runner().ok("a {b: rgb(0, 0, calc(infinity), 0.5)}\n"), @@ -121,7 +115,6 @@ mod green { use super::runner; #[test] - #[ignore] // unexepected error fn nan() { assert_eq!( runner().ok("a {b: rgb(0, calc(NaN), 0, 0.5)}\n"), @@ -131,7 +124,6 @@ mod green { ); } #[test] - #[ignore] // unexepected error fn negative_infinity() { assert_eq!( runner().ok("a {b: rgb(0, calc(-infinity), 0, 0.5)}\n"), @@ -141,7 +133,6 @@ mod green { ); } #[test] - #[ignore] // unexepected error fn positive_infinity() { assert_eq!( runner().ok("a {b: rgb(0, calc(infinity), 0, 0.5)}\n"), @@ -170,7 +161,6 @@ mod red { use super::runner; #[test] - #[ignore] // unexepected error fn nan() { assert_eq!( runner().ok("a {b: rgb(calc(NaN), 0, 0, 0.5)}\n"), @@ -180,7 +170,6 @@ mod red { ); } #[test] - #[ignore] // unexepected error fn negative_infinity() { assert_eq!( runner().ok("a {b: rgb(calc(-infinity), 0, 0, 0.5)}\n"), @@ -190,7 +179,6 @@ mod red { ); } #[test] - #[ignore] // unexepected error fn positive_infinity() { assert_eq!( runner().ok("a {b: rgb(calc(infinity), 0, 0, 0.5)}\n"),