Skip to content

Commit 29fab94

Browse files
committed
Rgba does not store Option as component
Legacy `rgb`/`rgba` syntax does not allow the "none" keyword and although the modern `rgb`/`rgba` syntax does support it, it is immediately converted to 0, because we never have to serialize back to "none" keywords for `rgb`/`rgba`. Also `RGBA` is now renamed to `Rgba` as per common rust naming conventions now that it is not used directly in Gecko any more.
1 parent a09f283 commit 29fab94

File tree

3 files changed

+79
-91
lines changed

3 files changed

+79
-91
lines changed

src/color.rs

+67-74
Original file line numberDiff line numberDiff line change
@@ -82,44 +82,34 @@ fn normalize_hue(hue: f32) -> f32 {
8282

8383
/// A color with red, green, blue, and alpha components, in a byte each.
8484
#[derive(Clone, Copy, PartialEq, Debug)]
85-
pub struct RGBA {
85+
pub struct Rgba {
8686
/// The red component.
87-
pub red: Option<u8>,
87+
pub red: u8,
8888
/// The green component.
89-
pub green: Option<u8>,
89+
pub green: u8,
9090
/// The blue component.
91-
pub blue: Option<u8>,
91+
pub blue: u8,
9292
/// The alpha component.
93-
pub alpha: Option<f32>,
93+
pub alpha: f32,
9494
}
9595

96-
impl RGBA {
96+
impl Rgba {
9797
/// Constructs a new RGBA value from float components. It expects the red,
9898
/// green, blue and alpha channels in that order, and all values will be
9999
/// clamped to the 0.0 ... 1.0 range.
100100
#[inline]
101-
pub fn from_floats(
102-
red: Option<f32>,
103-
green: Option<f32>,
104-
blue: Option<f32>,
105-
alpha: Option<f32>,
106-
) -> Self {
101+
pub fn from_floats(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
107102
Self::new(
108-
red.map(clamp_unit_f32),
109-
green.map(clamp_unit_f32),
110-
blue.map(clamp_unit_f32),
111-
alpha.map(|a| a.clamp(0.0, OPAQUE)),
103+
clamp_unit_f32(red),
104+
clamp_unit_f32(green),
105+
clamp_unit_f32(blue),
106+
alpha.clamp(0.0, OPAQUE),
112107
)
113108
}
114109

115110
/// Same thing, but with `u8` values instead of floats in the 0 to 1 range.
116111
#[inline]
117-
pub const fn new(
118-
red: Option<u8>,
119-
green: Option<u8>,
120-
blue: Option<u8>,
121-
alpha: Option<f32>,
122-
) -> Self {
112+
pub const fn new(red: u8, green: u8, blue: u8, alpha: f32) -> Self {
123113
Self {
124114
red,
125115
green,
@@ -130,7 +120,7 @@ impl RGBA {
130120
}
131121

132122
#[cfg(feature = "serde")]
133-
impl Serialize for RGBA {
123+
impl Serialize for Rgba {
134124
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
135125
where
136126
S: Serializer,
@@ -140,32 +130,32 @@ impl Serialize for RGBA {
140130
}
141131

142132
#[cfg(feature = "serde")]
143-
impl<'de> Deserialize<'de> for RGBA {
133+
impl<'de> Deserialize<'de> for Rgba {
144134
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
145135
where
146136
D: Deserializer<'de>,
147137
{
148138
let (r, g, b, a) = Deserialize::deserialize(deserializer)?;
149-
Ok(RGBA::new(r, g, b, a))
139+
Ok(Rgba::new(r, g, b, a))
150140
}
151141
}
152142

153-
impl ToCss for RGBA {
143+
impl ToCss for Rgba {
154144
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
155145
where
156146
W: fmt::Write,
157147
{
158-
let has_alpha = self.alpha.unwrap_or(0.0) != OPAQUE;
148+
let has_alpha = self.alpha != OPAQUE;
159149

160150
dest.write_str(if has_alpha { "rgba(" } else { "rgb(" })?;
161-
self.red.unwrap_or(0).to_css(dest)?;
151+
self.red.to_css(dest)?;
162152
dest.write_str(", ")?;
163-
self.green.unwrap_or(0).to_css(dest)?;
153+
self.green.to_css(dest)?;
164154
dest.write_str(", ")?;
165-
self.blue.unwrap_or(0).to_css(dest)?;
155+
self.blue.to_css(dest)?;
166156

167157
// Legacy syntax does not allow none components.
168-
serialize_color_alpha(dest, Some(self.alpha.unwrap_or(0.0)), true)?;
158+
serialize_color_alpha(dest, Some(self.alpha), true)?;
169159

170160
dest.write_char(')')
171161
}
@@ -213,7 +203,7 @@ impl ToCss for Hsl {
213203
self.lightness.unwrap_or(0.0),
214204
);
215205

216-
RGBA::from_floats(Some(red), Some(green), Some(blue), self.alpha).to_css(dest)
206+
Rgba::from_floats(red, green, blue, self.alpha.unwrap_or(OPAQUE)).to_css(dest)
217207
}
218208
}
219209

@@ -280,7 +270,7 @@ impl ToCss for Hwb {
280270
self.blackness.unwrap_or(0.0),
281271
);
282272

283-
RGBA::from_floats(Some(red), Some(green), Some(blue), self.alpha).to_css(dest)
273+
Rgba::from_floats(red, green, blue, self.alpha.unwrap_or(OPAQUE)).to_css(dest)
284274
}
285275
}
286276

@@ -621,7 +611,7 @@ pub enum Color {
621611
/// The 'currentcolor' keyword.
622612
CurrentColor,
623613
/// Specify sRGB colors directly by their red/green/blue/alpha chanels.
624-
Rgba(RGBA),
614+
Rgba(Rgba),
625615
/// Specifies a color in sRGB using hue, saturation and lightness components.
626616
Hsl(Hsl),
627617
/// Specifies a color in sRGB using hue, whiteness and blackness components.
@@ -812,7 +802,7 @@ pub trait FromParsedColor {
812802
fn from_current_color() -> Self;
813803

814804
/// Construct a new color from red, green, blue and alpha components.
815-
fn from_rgba(red: Option<u8>, green: Option<u8>, blue: Option<u8>, alpha: Option<f32>) -> Self;
805+
fn from_rgba(red: u8, green: u8, blue: u8, alpha: f32) -> Self;
816806

817807
/// Construct a new color from hue, saturation, lightness and alpha components.
818808
fn from_hsl(
@@ -876,28 +866,28 @@ where
876866
{
877867
Ok(match value.len() {
878868
8 => O::from_rgba(
879-
Some(from_hex(value[0])? * 16 + from_hex(value[1])?),
880-
Some(from_hex(value[2])? * 16 + from_hex(value[3])?),
881-
Some(from_hex(value[4])? * 16 + from_hex(value[5])?),
882-
Some((from_hex(value[6])? * 16 + from_hex(value[7])?) as f32 / 255.0),
869+
from_hex(value[0])? * 16 + from_hex(value[1])?,
870+
from_hex(value[2])? * 16 + from_hex(value[3])?,
871+
from_hex(value[4])? * 16 + from_hex(value[5])?,
872+
(from_hex(value[6])? * 16 + from_hex(value[7])?) as f32 / 255.0,
883873
),
884874
6 => O::from_rgba(
885-
Some(from_hex(value[0])? * 16 + from_hex(value[1])?),
886-
Some(from_hex(value[2])? * 16 + from_hex(value[3])?),
887-
Some(from_hex(value[4])? * 16 + from_hex(value[5])?),
888-
Some(OPAQUE),
875+
from_hex(value[0])? * 16 + from_hex(value[1])?,
876+
from_hex(value[2])? * 16 + from_hex(value[3])?,
877+
from_hex(value[4])? * 16 + from_hex(value[5])?,
878+
OPAQUE,
889879
),
890880
4 => O::from_rgba(
891-
Some(from_hex(value[0])? * 17),
892-
Some(from_hex(value[1])? * 17),
893-
Some(from_hex(value[2])? * 17),
894-
Some((from_hex(value[3])? * 17) as f32 / 255.0),
881+
from_hex(value[0])? * 17,
882+
from_hex(value[1])? * 17,
883+
from_hex(value[2])? * 17,
884+
(from_hex(value[3])? * 17) as f32 / 255.0,
895885
),
896886
3 => O::from_rgba(
897-
Some(from_hex(value[0])? * 17),
898-
Some(from_hex(value[1])? * 17),
899-
Some(from_hex(value[2])? * 17),
900-
Some(OPAQUE),
887+
from_hex(value[0])? * 17,
888+
from_hex(value[1])? * 17,
889+
from_hex(value[2])? * 17,
890+
OPAQUE,
901891
),
902892
_ => return Err(()),
903893
})
@@ -935,8 +925,8 @@ impl FromParsedColor for Color {
935925
}
936926

937927
#[inline]
938-
fn from_rgba(red: Option<u8>, green: Option<u8>, blue: Option<u8>, alpha: Option<f32>) -> Self {
939-
Color::Rgba(RGBA::new(red, green, blue, alpha))
928+
fn from_rgba(red: u8, green: u8, blue: u8, alpha: f32) -> Self {
929+
Color::Rgba(Rgba::new(red, green, blue, alpha))
940930
}
941931

942932
fn from_hsl(
@@ -1174,10 +1164,10 @@ where
11741164
}
11751165

11761166
match_ignore_ascii_case! { ident ,
1177-
"transparent" => Ok(Output::from_rgba(Some(0), Some(0), Some(0), Some(0.0))),
1167+
"transparent" => Ok(Output::from_rgba(0, 0, 0, 0.0)),
11781168
"currentcolor" => Ok(Output::from_current_color()),
11791169
_ => keyword(ident)
1180-
.map(|(r, g, b)| Output::from_rgba(Some(*r), Some(*g), Some(*b), Some(1.0)))
1170+
.map(|(r, g, b)| Output::from_rgba(*r, *g, *b, 1.0))
11811171
.ok_or(()),
11821172
}
11831173
}
@@ -1327,47 +1317,50 @@ where
13271317
// are parsing the legacy syntax.
13281318
let is_legacy_syntax = maybe_red.is_some() && arguments.try_parse(|p| p.expect_comma()).is_ok();
13291319

1330-
let red: Option<u8>;
1331-
let green: Option<u8>;
1332-
let blue: Option<u8>;
1333-
1334-
let alpha = if is_legacy_syntax {
1335-
match maybe_red.unwrap() {
1320+
let (red, green, blue, alpha) = if is_legacy_syntax {
1321+
let (red, green, blue) = match maybe_red.unwrap() {
13361322
NumberOrPercentage::Number { value } => {
1337-
red = Some(clamp_floor_256_f32(value));
1338-
green = Some(clamp_floor_256_f32(color_parser.parse_number(arguments)?));
1323+
let red = clamp_floor_256_f32(value);
1324+
let green = clamp_floor_256_f32(color_parser.parse_number(arguments)?);
13391325
arguments.expect_comma()?;
1340-
blue = Some(clamp_floor_256_f32(color_parser.parse_number(arguments)?));
1326+
let blue = clamp_floor_256_f32(color_parser.parse_number(arguments)?);
1327+
(red, green, blue)
13411328
}
13421329
NumberOrPercentage::Percentage { unit_value } => {
1343-
red = Some(clamp_unit_f32(unit_value));
1344-
green = Some(clamp_unit_f32(color_parser.parse_percentage(arguments)?));
1330+
let red = clamp_unit_f32(unit_value);
1331+
let green = clamp_unit_f32(color_parser.parse_percentage(arguments)?);
13451332
arguments.expect_comma()?;
1346-
blue = Some(clamp_unit_f32(color_parser.parse_percentage(arguments)?));
1333+
let blue = clamp_unit_f32(color_parser.parse_percentage(arguments)?);
1334+
(red, green, blue)
13471335
}
1348-
}
1336+
};
13491337

1350-
Some(parse_legacy_alpha(color_parser, arguments)?)
1338+
let alpha = parse_legacy_alpha(color_parser, arguments)?;
1339+
1340+
(red, green, blue, alpha)
13511341
} else {
13521342
#[inline]
1353-
fn get_component_value(c: Option<NumberOrPercentage>) -> Option<u8> {
1343+
fn get_component_value(c: Option<NumberOrPercentage>) -> u8 {
13541344
c.map(|c| match c {
13551345
NumberOrPercentage::Number { value } => clamp_floor_256_f32(value),
13561346
NumberOrPercentage::Percentage { unit_value } => clamp_unit_f32(unit_value),
13571347
})
1348+
.unwrap_or(0)
13581349
}
13591350

1360-
red = get_component_value(maybe_red);
1351+
let red = get_component_value(maybe_red);
13611352

1362-
green = get_component_value(parse_none_or(arguments, |p| {
1353+
let green = get_component_value(parse_none_or(arguments, |p| {
13631354
color_parser.parse_number_or_percentage(p)
13641355
})?);
13651356

1366-
blue = get_component_value(parse_none_or(arguments, |p| {
1357+
let blue = get_component_value(parse_none_or(arguments, |p| {
13671358
color_parser.parse_number_or_percentage(p)
13681359
})?);
13691360

1370-
parse_modern_alpha(color_parser, arguments)?
1361+
let alpha = parse_modern_alpha(color_parser, arguments)?.unwrap_or(0.0);
1362+
1363+
(red, green, blue, alpha)
13711364
};
13721365

13731366
Ok(P::Output::from_rgba(red, green, blue, alpha))

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ fn parse_border_spacing(_context: &ParserContext, input: &mut Parser)
7070
pub use crate::color::{
7171
hsl_to_rgb, hwb_to_rgb, parse_color_keyword, parse_color_with, parse_hash_color,
7272
serialize_color_alpha, AngleOrNumber, Color, ColorFunction, ColorParser, FromParsedColor, Hsl,
73-
Hwb, Lab, Lch, NumberOrPercentage, Oklab, Oklch, PredefinedColorSpace, RGBA,
73+
Hwb, Lab, Lch, NumberOrPercentage, Oklab, Oklch, PredefinedColorSpace, Rgba,
7474
};
7575
pub use crate::cow_rc_str::CowRcStr;
7676
pub use crate::from_bytes::{stylesheet_encoding, EncodingSupport};

src/tests.rs

+11-16
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ use super::{
1818
parse_important, parse_nth, parse_one_declaration, parse_one_rule, stylesheet_encoding,
1919
AtRuleParser, BasicParseError, BasicParseErrorKind, Color, CowRcStr, DeclarationParser,
2020
Delimiter, EncodingSupport, ParseError, ParseErrorKind, Parser, ParserInput, ParserState,
21-
QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser, SourceLocation, StyleSheetParser,
22-
ToCss, Token, TokenSerializationType, UnicodeRange, RGBA,
21+
QualifiedRuleParser, Rgba, RuleBodyItemParser, RuleBodyParser, SourceLocation,
22+
StyleSheetParser, ToCss, Token, TokenSerializationType, UnicodeRange,
2323
};
2424

2525
macro_rules! JArray {
@@ -592,19 +592,19 @@ fn serialize_current_color() {
592592

593593
#[test]
594594
fn serialize_rgb_full_alpha() {
595-
let c = Color::Rgba(RGBA::new(Some(255), Some(230), Some(204), Some(1.0)));
595+
let c = Color::Rgba(Rgba::new(255, 230, 204, 1.0));
596596
assert_eq!(c.to_css_string(), "rgb(255, 230, 204)");
597597
}
598598

599599
#[test]
600600
fn serialize_rgba() {
601-
let c = Color::Rgba(RGBA::new(Some(26), Some(51), Some(77), Some(0.125)));
601+
let c = Color::Rgba(Rgba::new(26, 51, 77, 0.125));
602602
assert_eq!(c.to_css_string(), "rgba(26, 51, 77, 0.125)");
603603
}
604604

605605
#[test]
606606
fn serialize_rgba_two_digit_float_if_roundtrips() {
607-
let c = Color::Rgba(RGBA::from_floats(Some(0.), Some(0.), Some(0.), Some(0.5)));
607+
let c = Color::Rgba(Rgba::from_floats(0., 0., 0., 0.5));
608608
assert_eq!(c.to_css_string(), "rgba(0, 0, 0, 0.5)");
609609
}
610610

@@ -1526,7 +1526,7 @@ fn generic_parser() {
15261526
#[derive(Debug, PartialEq)]
15271527
enum OutputType {
15281528
CurrentColor,
1529-
Rgba(Option<u8>, Option<u8>, Option<u8>, Option<f32>),
1529+
Rgba(u8, u8, u8, f32),
15301530
Hsl(Option<f32>, Option<f32>, Option<f32>, Option<f32>),
15311531
Hwb(Option<f32>, Option<f32>, Option<f32>, Option<f32>),
15321532
Lab(Option<f32>, Option<f32>, Option<f32>, Option<f32>),
@@ -1547,12 +1547,7 @@ fn generic_parser() {
15471547
OutputType::CurrentColor
15481548
}
15491549

1550-
fn from_rgba(
1551-
red: Option<u8>,
1552-
green: Option<u8>,
1553-
blue: Option<u8>,
1554-
alpha: Option<f32>,
1555-
) -> Self {
1550+
fn from_rgba(red: u8, green: u8, blue: u8, alpha: f32) -> Self {
15561551
OutputType::Rgba(red, green, blue, alpha)
15571552
}
15581553

@@ -1630,10 +1625,10 @@ fn generic_parser() {
16301625
#[rustfmt::skip]
16311626
const TESTS: &[(&str, OutputType)] = &[
16321627
("currentColor", OutputType::CurrentColor),
1633-
("rgb(1, 2, 3)", OutputType::Rgba(Some(1), Some(2), Some(3), Some(1.0))),
1634-
("rgba(1, 2, 3, 0.4)", OutputType::Rgba(Some(1), Some(2), Some(3), Some(0.4))),
1635-
("rgb(none none none / none)", OutputType::Rgba(None, None, None, None)),
1636-
("rgb(1 none 3 / none)", OutputType::Rgba(Some(1), None, Some(3), None)),
1628+
("rgb(1, 2, 3)", OutputType::Rgba(1, 2, 3, 1.0)),
1629+
("rgba(1, 2, 3, 0.4)", OutputType::Rgba(1, 2, 3, 0.4)),
1630+
("rgb(none none none / none)", OutputType::Rgba(0, 0, 0, 0.0)),
1631+
("rgb(1 none 3 / none)", OutputType::Rgba(1, 0, 3, 0.0)),
16371632

16381633
("hsla(45deg, 20%, 30%, 0.4)", OutputType::Hsl(Some(45.0), Some(0.2), Some(0.3), Some(0.4))),
16391634
("hsl(45deg none none)", OutputType::Hsl(Some(45.0), None, None, Some(1.0))),

0 commit comments

Comments
 (0)