feat(css/minifier): Compress hsl colors (#5142)

This commit is contained in:
Alexander Akait 2022-07-08 08:38:44 +03:00 committed by GitHub
parent de484bf98a
commit 714ff5321d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 231 additions and 64 deletions

View File

@ -87,12 +87,9 @@ impl VisitMut for CompressAngle {
return;
}
let from = match &*angle.unit.value.to_lowercase() {
"deg" => AngleType::Deg,
"grad" => AngleType::Grad,
"rad" => AngleType::Rad,
"turn" => AngleType::Turn,
_ => return,
let from = match get_angle_type(&*angle.unit.value.to_lowercase()) {
Some(angel_type) => angel_type,
None => return,
};
let deg = to_deg(angle.value.value, from);
@ -117,14 +114,14 @@ impl VisitMut for CompressAngle {
}
}
enum AngleType {
pub(crate) enum AngleType {
Deg,
Grad,
Rad,
Turn,
}
fn to_deg(value: f64, from: AngleType) -> f64 {
pub(crate) fn to_deg(value: f64, from: AngleType) -> f64 {
match from {
AngleType::Deg => value,
AngleType::Grad => value * 180.0 / 200.0,
@ -133,6 +130,16 @@ fn to_deg(value: f64, from: AngleType) -> f64 {
}
}
pub(crate) fn get_angle_type(unit: &str) -> Option<AngleType> {
match unit {
"deg" => Some(AngleType::Deg),
"grad" => Some(AngleType::Grad),
"rad" => Some(AngleType::Rad),
"turn" => Some(AngleType::Turn),
_ => None,
}
}
fn normalize_deg(mut value: f64) -> f64 {
value = (value % 360.0 + 360.0) % 360.0;

View File

@ -3,6 +3,8 @@ use swc_css_ast::*;
use swc_css_utils::NAMED_COLORS;
use swc_css_visit::{VisitMut, VisitMutWith};
use crate::compress::angle::{get_angle_type, to_deg};
fn get_short_hex(v: u32) -> u32 {
((v & 0x0ff00000) >> 12) | ((v & 0x00000ff0) >> 4)
}
@ -55,7 +57,63 @@ fn get_named_color_by_hex(v: u32) -> Option<&'static str> {
Some(s)
}
macro_rules! make_color_from_rgb {
static ONE_THIRD: f64 = 1.0 / 3.0;
static ONE_SECOND: f64 = 1.0 / 2.0;
static ONE_SIX: f64 = 1.0 / 6.0;
static TWO_THIRD: f64 = 2.0 / 3.0;
fn hsl_to_rgb(hsl: [f64; 3]) -> [f64; 3] {
let [h, s, l] = hsl;
let r;
let g;
let b;
if s == 0.0 {
r = l;
g = l;
b = l;
} else {
let hue2rgb = |p: f64, q: f64, mut t: f64| -> f64 {
if t < 0.0 {
t += 1.0;
}
if t > 1.0 {
t -= 1.0;
}
if t < ONE_SIX {
return p + (q - p) * 6.0 * t;
}
if t < ONE_SECOND {
return q;
}
if t < TWO_THIRD {
return p + (q - p) * (TWO_THIRD - t) * 6.0;
}
p
};
let q = if l < 0.5 {
l * (1.0 + s)
} else {
l + s - l * s
};
let p = 2.0 * l - q;
r = hue2rgb(p, q, h + ONE_THIRD);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - ONE_THIRD);
}
[r * 255.0, g * 255.0, b * 255.0]
}
macro_rules! make_color {
($span:expr,$r:expr,$g:expr,$b:expr) => {{
let hex: u32 = (($r as u32) << 16) | (($g as u32) << 8) | ($b as u32);
@ -82,7 +140,7 @@ macro_rules! make_color_from_rgb {
}};
}
macro_rules! make_color_from_rgba {
macro_rules! make_color_with_alpha {
($span:expr,$r:expr,$g:expr,$b:expr,$a:expr,$t:expr) => {{
// TODO improve when we will have browserslist
let is_alpha_hex_supported = false;
@ -232,12 +290,11 @@ impl VisitMut for CompressColor {
..
})) => match &*value.to_lowercase() {
"transparent" => {
*color = make_color_from_rgba!(*span, 0.0, 0.0, 0.0, 0.0, true);
*color = make_color_with_alpha!(*span, 0.0, 0.0, 0.0, 0.0, true);
}
name => {
if let Some(value) = NAMED_COLORS.get(name) {
*color =
make_color_from_rgb!(*span, value.rgb[0], value.rgb[1], value.rgb[2])
*color = make_color!(*span, value.rgb[0], value.rgb[1], value.rgb[2])
}
}
},
@ -316,14 +373,109 @@ impl VisitMut for CompressColor {
_ => return,
};
match (r, g, b, a) {
(Some(r), Some(g), Some(b), None) => {
*color = make_color_from_rgb!(*span, r, g, b);
if let (Some(r), Some(g), Some(b), a) = (r, g, b, a) {
if let Some(a) = a {
*color = make_color_with_alpha!(*span, r, g, b, a.0, a.1);
} else {
*color = make_color!(*span, r, g, b);
}
(Some(r), Some(g), Some(b), Some(a)) => {
*color = make_color_from_rgba!(*span, r, g, b, a.0, a.1);
}
}
Color::AbsoluteColorBase(AbsoluteColorBase::Function(Function {
span,
name,
value,
..
})) if matches!(&*name.value, "hsl" | "hsla") => {
let hsla: Vec<_> = value
.iter()
.filter(|n| {
!matches!(
n,
ComponentValue::Delimiter(Delimiter {
value: DelimiterValue::Comma | DelimiterValue::Solidus,
..
})
)
})
.collect();
let h = match hsla.get(0) {
Some(ComponentValue::Hue(hue)) => {
let mut value = match hue {
Hue::Number(Number { value, .. }) => *value,
Hue::Angle(Angle {
value: Number { value, .. },
unit: Ident { value: unit, .. },
..
}) => {
let angel_type = match get_angle_type(&unit.to_lowercase()) {
Some(angel_type) => angel_type,
_ => return,
};
to_deg(*value, angel_type)
}
};
value %= 360.0;
if value < 0.0 {
value += 360.0;
}
Some(value / 360.0)
}
_ => return,
};
let s = match hsla.get(1) {
Some(ComponentValue::Percentage(Percentage {
value: Number { value, .. },
..
})) => Some(*value / 100.0),
_ => return,
};
let l = match hsla.get(2) {
Some(ComponentValue::Percentage(Percentage {
value: Number { value, .. },
..
})) => Some(*value / 100.0),
_ => return,
};
let a = match hsla.get(3) {
Some(ComponentValue::AlphaValue(AlphaValue::Number(number))) => {
if number.value == 1.0 {
None
} else {
Some((number.value, true))
}
}
Some(ComponentValue::AlphaValue(AlphaValue::Percentage(percentage))) => {
if percentage.value.value == 100.0 {
None
} else {
Some((percentage.value.value / 100.0, false))
}
}
None => None,
_ => return,
};
if let (Some(h), Some(s), Some(l), a) = (h, s, l, a) {
let rgb = hsl_to_rgb([h, s, l]);
if let Some(a) = a {
*color = make_color_with_alpha!(
*span,
rgb[0].round(),
rgb[1].round(),
rgb[2].round(),
a.0,
a.1
);
} else {
*color = make_color!(*span, rgb[0].round(), rgb[1].round(), rgb[2].round());
}
_ => {}
}
}
_ => {}

View File

@ -122,54 +122,62 @@
color: rgb(from #FF0000 255 255 255);
}
.color-31 {
color: rgb(from red 255 255 255);
}
.class-31 {
color: hsl(362deg, 100%, 50%);
color: hsl(360, 0%, 50%);
color: hsl(360, 100%, 0%);
.color-32 {
color: rgb(from #f00 255 255 255);
}
color: hsl(90deg, 100%, 50%);
color: hsl(90grad, 100%, 50%);
color: hsl(1.0708rad, 100%, 50%);
color: hsl(0.25turn, 100%, 50%);
.color-33 {
color: rgb(from yellow 255 255 255);
}
color: hsl(0deg, 100%, 50%);
color: hsl(360deg, 100%, 50%);
color: hsl(720deg, 100%, 50%);
color: hsl(161deg, 100%, 50%);
.color-34 {
color: rgb(from snow 255 255 255);
}
color: hsl(360, 100%, 50%);
color: hsl(315, 100%, 50%);
color: hsl(270, 100%, 50%);
color: hsl(225, 100%, 50%);
color: hsl(180, 100%, 50%);
color: hsl(135, 100%, 50%);
color: hsl(90, 100%, 50%);
color: hsl(45, 100%, 50%);
color: hsl(0, 100%, 50%);
.color-35 {
color: rgb(from #D2B48C 255 255 255);
}
color: hsl(360, 100%, 50%, 1.0);
color: hsl(315, 100%, 50%, 100%);
color: hsl(270, 100%, 50%, 0.5);
color: hsl(225, 100%, 50%, 0.5);
color: hsl(180, 100%, 50%, 0.5);
color: hsl(135, 100%, 50%, 0.5);
color: hsl(90, 100%, 50%, 0.5);
color: hsl(45, 100%, 50%, 0.5);
color: hsl(0, 100%, 50%, 0.5);
.color-36 {
color: rgb(from #ff0000 255 255 255);
}
color: hsla(360, 100%, 50%);
color: hsla(315, 100%, 50%);
color: hsla(270, 100%, 50%);
color: hsla(225, 100%, 50%);
color: hsla(180, 100%, 50%);
color: hsla(135, 100%, 50%);
color: hsla(90, 100%, 50%);
color: hsla(45, 100%, 50%);
color: hsla(0, 100%, 50%);
.color-37 {
color: rgb(from white 255 255 255);
}
color: hsla(360, 100%, 50%, 1.0);
color: hsla(315, 100%, 50%, 100%);
color: hsla(270, 100%, 50%, 0.5);
color: hsla(225, 100%, 50%, 0.5);
color: hsla(180, 100%, 50%, 0.5);
color: hsla(135, 100%, 50%, 0.5);
color: hsla(90, 100%, 50%, 0.5);
color: hsla(45, 100%, 50%, 0.5);
color: hsla(0, 100%, 50%, 0.5);
.color-38 {
color: rgb(from #ffffff 255 255 255);
}
.color-39 {
color: rgb(from #fff 255 255 255);
}
.color-40 {
color: #ffffff;
}
.color-41 {
color: #fff;
}
.color-42 {
color: #ffffffff;
}
.color-43 {
color: #ffff;
}
color: hsl(361, 100%, 50%);
color: hsl(362, 100%, 50%);
color: hsl(363, 100%, 50%);
}

View File

@ -1 +1 @@
.color{color:rgb(from rgba(0,0,0,0)255 255 255)}.color-1{color:rgb(from red 255 255 255)}.color-2{color:rgb(from red 255 255 255)}.color-3{color:rgb(from#f00 255 255 255)}.color-4{color:rgb(from#eee8aa 255 255 255)}.color-5{color:rgb(from#ff0 255 255 255)}.color-6{color:rgb(from snow 255 255 255)}.color-7{color:rgba(123,123,123,0)}.color-8{color:#7b7b7b}.color-9{color:#7b7b7b}.color-10{color:#7b7b7b}.color-11{color:#7b7b7b}.color-12{color:rgba(51,102,77,23%)}.color-13{color:#7b7b7b}.color-14{color:#6496c8}.class-15{color:#7b7b7b}.class-16{color:rgba(123,123,123,99%)}.class-17{color:#7b7b7b}.class-18{color:rgba(179,82,31,13%)}.class-19{color:rgba(180,82,31,13%)}.class-20{color:rgba(181,82,31,13%)}.class-21{color:rgba(182,82,31,13%)}.class-22{color:rgba(184,82,31,13%)}.class-23{color:rgba(181.4,181,181,13%)}.class-24{color:rgba(181.5,181,181,13%)}.class-25{color:rgba(181,181,181,.1%)}.class-26{color:rgba(181,181,181,.4%)}.color-27{color:rgb(from#eee8aa 255 255 255)}.color-28{color:rgb(from teal 255 255 255)}.color-29{color:rgb(from red 255 255 255)}.color-30{color:rgb(from red 255 255 255)}.color-31{color:rgb(from red 255 255 255)}.color-32{color:rgb(from#f00 255 255 255)}.color-33{color:rgb(from#ff0 255 255 255)}.color-34{color:rgb(from snow 255 255 255)}.color-35{color:rgb(from tan 255 255 255)}.color-36{color:rgb(from red 255 255 255)}.color-37{color:rgb(from#fff 255 255 255)}.color-38{color:rgb(from#fff 255 255 255)}.color-39{color:rgb(from#fff 255 255 255)}.color-40{color:#fff}.color-41{color:#fff}.color-42{color:#fff}.color-43{color:#ffff}
.color{color:rgb(from rgba(0,0,0,0)255 255 255)}.color-1{color:rgb(from red 255 255 255)}.color-2{color:rgb(from red 255 255 255)}.color-3{color:rgb(from#f00 255 255 255)}.color-4{color:rgb(from#eee8aa 255 255 255)}.color-5{color:rgb(from#ff0 255 255 255)}.color-6{color:rgb(from snow 255 255 255)}.color-7{color:rgba(123,123,123,0)}.color-8{color:#7b7b7b}.color-9{color:#7b7b7b}.color-10{color:#7b7b7b}.color-11{color:#7b7b7b}.color-12{color:rgba(51,102,77,23%)}.color-13{color:#7b7b7b}.color-14{color:#6496c8}.class-15{color:#7b7b7b}.class-16{color:rgba(123,123,123,99%)}.class-17{color:#7b7b7b}.class-18{color:rgba(179,82,31,13%)}.class-19{color:rgba(180,82,31,13%)}.class-20{color:rgba(181,82,31,13%)}.class-21{color:rgba(182,82,31,13%)}.class-22{color:rgba(184,82,31,13%)}.class-23{color:rgba(181.4,181,181,13%)}.class-24{color:rgba(181.5,181,181,13%)}.class-25{color:rgba(181,181,181,.1%)}.class-26{color:rgba(181,181,181,.4%)}.color-27{color:rgb(from#eee8aa 255 255 255)}.color-28{color:rgb(from teal 255 255 255)}.color-29{color:rgb(from red 255 255 255)}.color-30{color:rgb(from red 255 255 255)}.class-31{color:#ff0900;color:gray;color:#000;color:#80ff00;color:#a6ff00;color:#f9ff00;color:#80ff00;color:red;color:red;color:red;color:#00ffae;color:red;color:#ff00bf;color:#7f00ff;color:#0040ff;color:#0ff;color:#00ff40;color:#80ff00;color:#ffbf00;color:red;color:red;color:#ff00bf;color:rgba(127,0,255,.5);color:rgba(0,64,255,.5);color:rgba(0,255,255,.5);color:rgba(0,255,64,.5);color:rgba(128,255,0,.5);color:rgba(255,191,0,.5);color:rgba(255,0,0,.5);color:red;color:#ff00bf;color:#7f00ff;color:#0040ff;color:#0ff;color:#00ff40;color:#80ff00;color:#ffbf00;color:red;color:red;color:#ff00bf;color:rgba(127,0,255,.5);color:rgba(0,64,255,.5);color:rgba(0,255,255,.5);color:rgba(0,255,64,.5);color:rgba(128,255,0,.5);color:rgba(255,191,0,.5);color:rgba(255,0,0,.5);color:#ff0400;color:#ff0900;color:#ff0d00}