Skip to content

Commit

Permalink
css: reuse color generation for hex lowering
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Dec 7, 2023
1 parent 16377c7 commit 2e59c93
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 48 deletions.
2 changes: 1 addition & 1 deletion internal/css_ast/css_ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ func TokensAreCommaSeparated(tokens []Token) bool {
return false
}

func (t Token) FractionForPercentage() (float64, bool) {
func (t Token) ClampedFractionForPercentage() (float64, bool) {
if t.Kind == css_lexer.TPercentage {
if f, err := strconv.ParseFloat(t.PercentageValue(), 64); err == nil {
if f < 0 {
Expand Down
18 changes: 2 additions & 16 deletions internal/css_parser/css_decls.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,7 @@ func (p *parser) processDeclarations(rules []css_ast.Rule, composesContext *comp

case css_ast.DBackground:
for i, t := range decl.Value {
decl.Value[i] = p.lowerColor(t)

if p.options.minifySyntax {
t := decl.Value[i]
if hex, ok := parseColor(t); ok {
decl.Value[i] = p.generateColor(t, hex)
}
}
decl.Value[i] = p.lowerAndMinifyColor(t)
}

case css_ast.DBackgroundColor,
Expand All @@ -185,14 +178,7 @@ func (p *parser) processDeclarations(rules []css_ast.Rule, composesContext *comp
css_ast.DTextEmphasisColor:

if len(decl.Value) == 1 {
decl.Value[0] = p.lowerColor(decl.Value[0])

if p.options.minifySyntax {
t := decl.Value[0]
if hex, ok := parseColor(t); ok {
decl.Value[0] = p.generateColor(t, hex)
}
}
decl.Value[0] = p.lowerAndMinifyColor(decl.Value[0])
}

case css_ast.DTransform:
Expand Down
38 changes: 15 additions & 23 deletions internal/css_parser/css_decls_color.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ func lowerAlphaPercentageToNumber(token css_ast.Token) css_ast.Token {
}

// Convert newer color syntax to older color syntax for older browsers
func (p *parser) lowerColor(token css_ast.Token) css_ast.Token {
func (p *parser) lowerAndMinifyColor(token css_ast.Token) css_ast.Token {
text := token.Text

switch token.Kind {
Expand All @@ -287,29 +287,13 @@ func (p *parser) lowerColor(token css_ast.Token) css_ast.Token {
// "#1234" => "rgba(1, 2, 3, 0.004)"
if hex, ok := parseHex(text); ok {
hex = expandHex(hex)
token.Kind = css_lexer.TFunction
token.Text = "rgba"
commaToken := p.commaToken(token.Loc)
token.Children = &[]css_ast.Token{
{Loc: token.Loc, Kind: css_lexer.TNumber, Text: strconv.Itoa(hexR(hex))}, commaToken,
{Loc: token.Loc, Kind: css_lexer.TNumber, Text: strconv.Itoa(hexG(hex))}, commaToken,
{Loc: token.Loc, Kind: css_lexer.TNumber, Text: strconv.Itoa(hexB(hex))}, commaToken,
{Loc: token.Loc, Kind: css_lexer.TNumber, Text: floatToStringForColor(float64(hexA(hex)) / 255)},
}
return p.generateColor(token, hex)
}

case 8:
// "#12345678" => "rgba(18, 52, 86, 0.47)"
if hex, ok := parseHex(text); ok {
token.Kind = css_lexer.TFunction
token.Text = "rgba"
commaToken := p.commaToken(token.Loc)
token.Children = &[]css_ast.Token{
{Loc: token.Loc, Kind: css_lexer.TNumber, Text: strconv.Itoa(hexR(hex))}, commaToken,
{Loc: token.Loc, Kind: css_lexer.TNumber, Text: strconv.Itoa(hexG(hex))}, commaToken,
{Loc: token.Loc, Kind: css_lexer.TNumber, Text: strconv.Itoa(hexB(hex))}, commaToken,
{Loc: token.Loc, Kind: css_lexer.TNumber, Text: floatToStringForColor(float64(hexA(hex)) / 255)},
}
return p.generateColor(token, hex)
}
}
}
Expand Down Expand Up @@ -417,6 +401,14 @@ func (p *parser) lowerColor(token css_ast.Token) css_ast.Token {
}
}

// When minifying, try to parse the color and print it back out. This minifies
// the color because we always print it out using the shortest encoding.
if p.options.minifySyntax {
if hex, ok := parseColor(token); ok {
token = p.generateColor(token, hex)
}
}

return token
}

Expand Down Expand Up @@ -526,8 +518,8 @@ func parseColor(token css_ast.Token) (uint32, bool) {

// HSL => RGB
if h, ok := degreesForAngle(h); ok {
if s, ok := s.FractionForPercentage(); ok {
if l, ok := l.FractionForPercentage(); ok {
if s, ok := s.ClampedFractionForPercentage(); ok {
if l, ok := l.ClampedFractionForPercentage(); ok {
if a, ok := parseAlphaByte(a); ok {
rf, gf, bf := hslToRgb(h, s, l)
r := floatToByte(rf)
Expand Down Expand Up @@ -557,8 +549,8 @@ func parseColor(token css_ast.Token) (uint32, bool) {

// HWB => RGB
if h, ok := degreesForAngle(h); ok {
if white, ok := s.FractionForPercentage(); ok {
if black, ok := l.FractionForPercentage(); ok {
if white, ok := s.ClampedFractionForPercentage(); ok {
if black, ok := l.ClampedFractionForPercentage(); ok {
if a, ok := parseAlphaByte(a); ok {
rf, gf, bf := hwbToRgb(h, white, black)
r := floatToByte(rf)
Expand Down
14 changes: 7 additions & 7 deletions internal/css_parser/css_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -583,12 +583,12 @@ func TestColorHSLA(t *testing.T) {
func TestLowerColor(t *testing.T) {
expectPrintedLower(t, "a { color: rebeccapurple }", "a {\n color: #663399;\n}\n", "")

expectPrintedLower(t, "a { color: #0123 }", "a {\n color: rgba(0, 17, 34, 0.2);\n}\n", "")
expectPrintedLower(t, "a { color: #0123 }", "a {\n color: rgba(0, 17, 34, .2);\n}\n", "")
expectPrintedLower(t, "a { color: #1230 }", "a {\n color: rgba(17, 34, 51, 0);\n}\n", "")
expectPrintedLower(t, "a { color: #1234 }", "a {\n color: rgba(17, 34, 51, 0.267);\n}\n", "")
expectPrintedLower(t, "a { color: #123f }", "a {\n color: rgba(17, 34, 51, 1);\n}\n", "")
expectPrintedLower(t, "a { color: #12345678 }", "a {\n color: rgba(18, 52, 86, 0.471);\n}\n", "")
expectPrintedLower(t, "a { color: #ff00007f }", "a {\n color: rgba(255, 0, 0, 0.498);\n}\n", "")
expectPrintedLower(t, "a { color: #1234 }", "a {\n color: rgba(17, 34, 51, .267);\n}\n", "")
expectPrintedLower(t, "a { color: #123f }", "a {\n color: #112233;\n}\n", "")
expectPrintedLower(t, "a { color: #12345678 }", "a {\n color: rgba(18, 52, 86, .47);\n}\n", "")
expectPrintedLower(t, "a { color: #ff00007f }", "a {\n color: rgba(255, 0, 0, .498);\n}\n", "")

expectPrintedLower(t, "a { color: rgb(1 2 3) }", "a {\n color: rgb(1, 2, 3);\n}\n", "")
expectPrintedLower(t, "a { color: hsl(1 2% 3%) }", "a {\n color: hsl(1, 2%, 3%);\n}\n", "")
Expand Down Expand Up @@ -633,11 +633,11 @@ func TestLowerColor(t *testing.T) {
func TestBackground(t *testing.T) {
expectPrinted(t, "a { background: #11223344 }", "a {\n background: #11223344;\n}\n", "")
expectPrintedMangle(t, "a { background: #11223344 }", "a {\n background: #1234;\n}\n", "")
expectPrintedLower(t, "a { background: #11223344 }", "a {\n background: rgba(17, 34, 51, 0.267);\n}\n", "")
expectPrintedLower(t, "a { background: #11223344 }", "a {\n background: rgba(17, 34, 51, .267);\n}\n", "")

expectPrinted(t, "a { background: border-box #11223344 }", "a {\n background: border-box #11223344;\n}\n", "")
expectPrintedMangle(t, "a { background: border-box #11223344 }", "a {\n background: border-box #1234;\n}\n", "")
expectPrintedLower(t, "a { background: border-box #11223344 }", "a {\n background: border-box rgba(17, 34, 51, 0.267);\n}\n", "")
expectPrintedLower(t, "a { background: border-box #11223344 }", "a {\n background: border-box rgba(17, 34, 51, .267);\n}\n", "")
}

func TestDeclaration(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion scripts/js-api-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -6784,7 +6784,7 @@ class Foo {

// CSS: lower
check({ supported: { 'hex-rgba': true }, loader: 'css' }, `a { color: #1234 }`, `a {\n color: #1234;\n}\n`),
check({ supported: { 'hex-rgba': false }, loader: 'css' }, `a { color: #1234 }`, `a {\n color: rgba(17, 34, 51, 0.267);\n}\n`),
check({ supported: { 'hex-rgba': false }, loader: 'css' }, `a { color: #1234 }`, `a {\n color: rgba(17, 34, 51, .267);\n}\n`),
check({ target: 'safari15.3', loader: 'css' }, `a { mask-image: url(x.png) }`, `a {\n -webkit-mask-image: url(x.png);\n mask-image: url(x.png);\n}\n`),
check({ target: 'safari15.4', loader: 'css' }, `a { mask-image: url(x.png) }`, `a {\n mask-image: url(x.png);\n}\n`),

Expand Down

0 comments on commit 2e59c93

Please sign in to comment.