Skip to content

Remove AbsoluteColor abstraction #321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 37 additions & 71 deletions src/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,10 +467,12 @@ impl ToCss for ColorFunction {
}
}

/// An absolutely specified color.
/// https://w3c.github.io/csswg-drafts/css-color-4/#typedef-absolute-color-base
/// A <color> value.
/// https://drafts.csswg.org/css-color-4/#color-type
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum AbsoluteColor {
pub enum Color {
/// The 'currentcolor' keyword.
CurrentColor,
/// Specify sRGB colors directly by their red/green/blue/alpha chanels.
Rgba(RGBA),
/// Specifies a CIELAB color by CIE Lightness and its a- and b-axis hue
Expand All @@ -491,64 +493,19 @@ pub enum AbsoluteColor {
ColorFunction(ColorFunction),
}

impl AbsoluteColor {
/// Return the alpha component of any of the schemes within.
pub fn alpha(&self) -> f32 {
match self {
Self::Rgba(c) => c.alpha,
Self::Lab(c) => c.alpha,
Self::Lch(c) => c.alpha,
Self::Oklab(c) => c.alpha,
Self::Oklch(c) => c.alpha,
Self::ColorFunction(c) => c.alpha,
}
}
}

impl ToCss for AbsoluteColor {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where
W: fmt::Write,
{
match self {
Self::Rgba(rgba) => rgba.to_css(dest),
Self::Lab(lab) => lab.to_css(dest),
Self::Lch(lch) => lch.to_css(dest),
Self::Oklab(lab) => lab.to_css(dest),
Self::Oklch(lch) => lch.to_css(dest),
Self::ColorFunction(color_function) => color_function.to_css(dest),
}
}
}

#[inline]
pub(crate) const fn rgb(red: u8, green: u8, blue: u8) -> Color {
rgba(red, green, blue, OPAQUE)
}

#[inline]
pub(crate) const fn rgba(red: u8, green: u8, blue: u8, alpha: f32) -> Color {
Color::Absolute(AbsoluteColor::Rgba(RGBA::new(red, green, blue, alpha)))
}

/// A <color> value.
/// https://w3c.github.io/csswg-drafts/css-color-4/#color-type
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Color {
/// The 'currentcolor' keyword.
CurrentColor,
/// An absolutely specified color.
Absolute(AbsoluteColor),
}

impl ToCss for Color {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where
W: fmt::Write,
{
match *self {
Color::CurrentColor => dest.write_str("currentcolor"),
Color::Absolute(absolute) => absolute.to_css(dest),
Color::Rgba(rgba) => rgba.to_css(dest),
Color::Lab(lab) => lab.to_css(dest),
Color::Lch(lch) => lch.to_css(dest),
Color::Oklab(lab) => lab.to_css(dest),
Color::Oklch(lch) => lch.to_css(dest),
Color::ColorFunction(color_function) => color_function.to_css(dest),
}
}
}
Expand Down Expand Up @@ -686,8 +643,9 @@ impl Color {
let location = input.current_source_location();
let token = input.next()?;
match *token {
Token::Hash(ref value) | Token::IDHash(ref value) => RGBA::parse_hash(value.as_bytes())
.map(|rgba| Color::Absolute(AbsoluteColor::Rgba(rgba))),
Token::Hash(ref value) | Token::IDHash(ref value) => {
RGBA::parse_hash(value.as_bytes()).map(|rgba| Color::Rgba(rgba))
}
Token::Ident(ref value) => parse_color_keyword(&*value),
Token::Function(ref name) => {
let name = name.clone();
Expand All @@ -714,6 +672,16 @@ impl Color {
/// (For example, the value of an `Ident` token is fine.)
#[inline]
pub fn parse_color_keyword(ident: &str) -> Result<Color, ()> {
#[inline]
pub(crate) const fn rgb(red: u8, green: u8, blue: u8) -> Color {
rgba(red, green, blue, OPAQUE)
}

#[inline]
pub(crate) const fn rgba(red: u8, green: u8, blue: u8, alpha: f32) -> Color {
Color::Rgba(RGBA::new(red, green, blue, alpha))
}

ascii_case_insensitive_phf_map! {
keyword -> Color = {
"black" => rgb(0, 0, 0),
Expand Down Expand Up @@ -927,25 +895,25 @@ where
// for L: 0% = 0.0, 100% = 100.0
// for a and b: -100% = -125, 100% = 125
"lab" => parse_lab_like(component_parser, arguments, 100.0, 125.0, |l, a, b, alpha| {
Color::Absolute(AbsoluteColor::Lab(Lab::new(l.max(0.), a , b , alpha)))
Color::Lab(Lab::new(l.max(0.), a , b , alpha))
}),

// for L: 0% = 0.0, 100% = 100.0
// for C: 0% = 0, 100% = 150
"lch" => parse_lch_like(component_parser, arguments, 100.0, 150.0, |l, c, h, alpha| {
Color::Absolute(AbsoluteColor::Lch(Lch::new(l.max(0.), c.max(0.), h, alpha)))
Color::Lch(Lch::new(l.max(0.), c.max(0.), h, alpha))
}),

// for L: 0% = 0.0, 100% = 1.0
// for a and b: -100% = -0.4, 100% = 0.4
"oklab" => parse_lab_like(component_parser, arguments, 1.0, 0.4, |l, a, b, alpha| {
Color::Absolute(AbsoluteColor::Oklab(Oklab::new(l.max(0.), a, b, alpha)))
Color::Oklab(Oklab::new(l.max(0.), a, b, alpha))
}),

// for L: 0% = 0.0, 100% = 1.0
// for C: 0% = 0.0 100% = 0.4
"oklch" => parse_lch_like(component_parser, arguments, 1.0, 0.4, |l, c, h, alpha| {
Color::Absolute(AbsoluteColor::Oklch(Oklch::new(l.max(0.), c.max(0.), h, alpha)))
Color::Oklch(Oklch::new(l.max(0.), c.max(0.), h, alpha))
}),

"color" => parse_color_function(component_parser, arguments),
Expand Down Expand Up @@ -1029,7 +997,7 @@ where
ComponentParser: ColorComponentParser<'i>,
{
let (red, green, blue, alpha) = parse_rgb_components_rgb(component_parser, arguments)?;
Ok(rgba(red, green, blue, alpha))
Ok(Color::Rgba(RGBA::new(red, green, blue, alpha)))
}

/// Parses hsl and hbw syntax, which happens to be identical.
Expand Down Expand Up @@ -1076,7 +1044,7 @@ where

let alpha = parse_alpha(component_parser, arguments, uses_commas)?;

Ok(rgba(red, green, blue, alpha))
Ok(Color::Rgba(RGBA::new(red, green, blue, alpha)))
}

/// https://drafts.csswg.org/css-color-4/#hwb-to-rgb
Expand Down Expand Up @@ -1223,13 +1191,11 @@ where

let alpha = parse_alpha(component_parser, arguments, false)?;

Ok(Color::Absolute(AbsoluteColor::ColorFunction(
ColorFunction {
color_space,
c1,
c2,
c3,
alpha,
},
)))
Ok(Color::ColorFunction(ColorFunction {
color_space,
c1,
c2,
c3,
alpha,
}))
}
5 changes: 2 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,8 @@ fn parse_border_spacing(_context: &ParserContext, input: &mut Parser)
#![recursion_limit = "200"] // For color::parse_color_keyword

pub use crate::color::{
hsl_to_rgb, hwb_to_rgb, parse_color_keyword, AbsoluteColor, AngleOrNumber, Color,
ColorComponentParser, ColorFunction, Lab, Lch, NumberOrPercentage, Oklab, Oklch,
PredefinedColorSpace, RGBA,
hsl_to_rgb, hwb_to_rgb, parse_color_keyword, AngleOrNumber, Color, ColorComponentParser,
ColorFunction, Lab, Lch, NumberOrPercentage, Oklab, Oklch, PredefinedColorSpace, RGBA,
};
pub use crate::cow_rc_str::CowRcStr;
pub use crate::from_bytes::{stylesheet_encoding, EncodingSupport};
Expand Down
37 changes: 17 additions & 20 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,11 @@ use serde_json::{self, json, Map, Value};
use self::test::Bencher;

use super::{
color::{rgb, rgba},
parse_important, parse_nth, parse_one_declaration, parse_one_rule, stylesheet_encoding,
AbsoluteColor, AtRuleParser, BasicParseError, BasicParseErrorKind, Color, CowRcStr,
DeclarationListParser, DeclarationParser, Delimiter, EncodingSupport, ParseError,
ParseErrorKind, Parser, ParserInput, ParserState, QualifiedRuleParser, RuleListParser,
SourceLocation, ToCss, Token, TokenSerializationType, UnicodeRange, RGBA,
AtRuleParser, BasicParseError, BasicParseErrorKind, Color, CowRcStr, DeclarationListParser,
DeclarationParser, Delimiter, EncodingSupport, ParseError, ParseErrorKind, Parser, ParserInput,
ParserState, QualifiedRuleParser, RuleListParser, SourceLocation, ToCss, Token,
TokenSerializationType, UnicodeRange, RGBA,
};

macro_rules! JArray {
Expand Down Expand Up @@ -590,19 +589,19 @@ fn serialize_current_color() {

#[test]
fn serialize_rgb_full_alpha() {
let c = rgb(255, 230, 204);
let c = Color::Rgba(RGBA::new(255, 230, 204, 1.0));
assert_eq!(c.to_css_string(), "rgb(255, 230, 204)");
}

#[test]
fn serialize_rgba() {
let c = rgba(26, 51, 77, 0.125);
let c = Color::Rgba(RGBA::new(26, 51, 77, 0.125));
assert_eq!(c.to_css_string(), "rgba(26, 51, 77, 0.125)");
}

#[test]
fn serialize_rgba_two_digit_float_if_roundtrips() {
let c = Color::Absolute(AbsoluteColor::Rgba(RGBA::from_floats(0., 0., 0., 0.5)));
let c = Color::Rgba(RGBA::from_floats(0., 0., 0., 0.5));
assert_eq!(c.to_css_string(), "rgba(0, 0, 0, 0.5)");
}

Expand Down Expand Up @@ -895,18 +894,16 @@ impl ToJson for Color {
fn to_json(&self) -> Value {
match *self {
Color::CurrentColor => "currentcolor".to_json(),
Color::Absolute(absolute) => match absolute {
AbsoluteColor::Rgba(ref rgba) => {
json!([rgba.red, rgba.green, rgba.blue, rgba.alpha])
}
AbsoluteColor::Lab(ref c) => json!([c.lightness, c.a, c.b, c.alpha]),
AbsoluteColor::Lch(ref c) => json!([c.lightness, c.chroma, c.hue, c.alpha]),
AbsoluteColor::Oklab(ref c) => json!([c.lightness, c.a, c.b, c.alpha]),
AbsoluteColor::Oklch(ref c) => json!([c.lightness, c.chroma, c.hue, c.alpha]),
AbsoluteColor::ColorFunction(ref c) => {
json!([c.color_space.as_str(), c.c1, c.c2, c.c3, c.alpha])
}
},
Color::Rgba(ref rgba) => {
json!([rgba.red, rgba.green, rgba.blue, rgba.alpha])
}
Color::Lab(ref c) => json!([c.lightness, c.a, c.b, c.alpha]),
Color::Lch(ref c) => json!([c.lightness, c.chroma, c.hue, c.alpha]),
Color::Oklab(ref c) => json!([c.lightness, c.a, c.b, c.alpha]),
Color::Oklch(ref c) => json!([c.lightness, c.chroma, c.hue, c.alpha]),
Color::ColorFunction(ref c) => {
json!([c.color_space.as_str(), c.c1, c.c2, c.c3, c.alpha])
}
}
}
}
Expand Down