aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/tdewolff/minify/css/css.go
diff options
context:
space:
mode:
authorGravatar Frédéric Guillot <fred@miniflux.net>2018-07-05 22:18:51 -0700
committerGravatar Frédéric Guillot <fred@miniflux.net>2018-07-05 22:18:51 -0700
commit53deb0b8cd1899ec325eca93631b3e137bdd3ec3 (patch)
tree23894ed57040ea689e9f60243656e1889d39a275 /vendor/github.com/tdewolff/minify/css/css.go
parente1c56b2e53ba3c6f48d5e159d18ae59c180cc388 (diff)
Refactor assets bundler and split Javascript files
Diffstat (limited to 'vendor/github.com/tdewolff/minify/css/css.go')
-rw-r--r--vendor/github.com/tdewolff/minify/css/css.go520
1 files changed, 321 insertions, 199 deletions
diff --git a/vendor/github.com/tdewolff/minify/css/css.go b/vendor/github.com/tdewolff/minify/css/css.go
index de0a8c8..1c34166 100644
--- a/vendor/github.com/tdewolff/minify/css/css.go
+++ b/vendor/github.com/tdewolff/minify/css/css.go
@@ -4,6 +4,7 @@ package css // import "github.com/tdewolff/minify/css"
import (
"bytes"
"encoding/hex"
+ "fmt"
"io"
"strconv"
@@ -29,16 +30,19 @@ type cssMinifier struct {
w io.Writer
p *css.Parser
o *Minifier
+
+ valuesBuffer []Token
}
////////////////////////////////////////////////////////////////
// DefaultMinifier is the default minifier.
-var DefaultMinifier = &Minifier{Decimals: -1}
+var DefaultMinifier = &Minifier{Decimals: -1, KeepCSS2: false}
// Minifier is a CSS minifier.
type Minifier struct {
Decimals int
+ KeepCSS2 bool
}
// Minify minifies CSS data, it reads from r and writes to w.
@@ -108,7 +112,19 @@ func (c *cssMinifier) minifyGrammar() error {
if _, err := c.w.Write(data); err != nil {
return err
}
- for _, val := range c.p.Values() {
+ values := c.p.Values()
+ if css.ToHash(data[1:]) == css.Import && len(values) == 2 && values[1].TokenType == css.URLToken {
+ url := values[1].Data
+ if url[4] != '"' && url[4] != '\'' {
+ url = url[3:]
+ url[0] = '"'
+ url[len(url)-1] = '"'
+ } else {
+ url = url[4 : len(url)-1]
+ }
+ values[1].Data = url
+ }
+ for _, val := range values {
if _, err := c.w.Write(val.Data); err != nil {
return err
}
@@ -216,138 +232,238 @@ func (c *cssMinifier) minifySelectors(property []byte, values []css.Token) error
return nil
}
-func (c *cssMinifier) minifyDeclaration(property []byte, values []css.Token) error {
- if len(values) == 0 {
+type Token struct {
+ css.TokenType
+ Data []byte
+ Components []css.Token // only filled for functions
+}
+
+func (t Token) String() string {
+ if len(t.Components) == 0 {
+ return t.TokenType.String() + "(" + string(t.Data) + ")"
+ } else {
+ return fmt.Sprint(t.Components)
+ }
+}
+
+func (c *cssMinifier) minifyDeclaration(property []byte, components []css.Token) error {
+ if len(components) == 0 {
return nil
}
+
prop := css.ToHash(property)
- inProgid := false
- for i, value := range values {
- if inProgid {
- if value.TokenType == css.FunctionToken {
- inProgid = false
- }
- continue
- } else if value.TokenType == css.IdentToken && css.ToHash(value.Data) == css.Progid {
- inProgid = true
- continue
+
+ // Strip !important from the component list, this will be added later separately
+ important := false
+ if len(components) > 2 && components[len(components)-2].TokenType == css.DelimToken && components[len(components)-2].Data[0] == '!' && css.ToHash(components[len(components)-1].Data) == css.Important {
+ components = components[:len(components)-2]
+ important = true
+ }
+
+ // Check if this is a simple list of values separated by whitespace or commas, otherwise we'll not be processing
+ simple := true
+ prevSep := true
+ values := c.valuesBuffer[:0]
+ for i := 0; i < len(components); i++ {
+ comp := components[i]
+ if comp.TokenType == css.LeftParenthesisToken || comp.TokenType == css.LeftBraceToken || comp.TokenType == css.LeftBracketToken || comp.TokenType == css.RightParenthesisToken || comp.TokenType == css.RightBraceToken || comp.TokenType == css.RightBracketToken {
+ simple = false
+ break
}
- value.TokenType, value.Data = c.shortenToken(prop, value.TokenType, value.Data)
- if prop == css.Font || prop == css.Font_Family || prop == css.Font_Weight {
- if value.TokenType == css.IdentToken && (prop == css.Font || prop == css.Font_Weight) {
- val := css.ToHash(value.Data)
- if val == css.Normal && prop == css.Font_Weight {
- // normal could also be specified for font-variant, not just font-weight
- value.TokenType = css.NumberToken
- value.Data = []byte("400")
- } else if val == css.Bold {
- value.TokenType = css.NumberToken
- value.Data = []byte("700")
- }
- } else if value.TokenType == css.StringToken && (prop == css.Font || prop == css.Font_Family) && len(value.Data) > 2 {
- unquote := true
- parse.ToLower(value.Data)
- s := value.Data[1 : len(value.Data)-1]
- if len(s) > 0 {
- for _, split := range bytes.Split(s, spaceBytes) {
- val := css.ToHash(split)
- // if len is zero, it contains two consecutive spaces
- if val == css.Inherit || val == css.Serif || val == css.Sans_Serif || val == css.Monospace || val == css.Fantasy || val == css.Cursive || val == css.Initial || val == css.Default ||
- len(split) == 0 || !css.IsIdent(split) {
- unquote = false
- break
- }
+
+ if !prevSep && comp.TokenType != css.WhitespaceToken && comp.TokenType != css.CommaToken {
+ simple = false
+ break
+ }
+
+ if comp.TokenType == css.WhitespaceToken || comp.TokenType == css.CommaToken {
+ prevSep = true
+ if comp.TokenType == css.CommaToken {
+ values = append(values, Token{components[i].TokenType, components[i].Data, nil})
+ }
+ } else if comp.TokenType == css.FunctionToken {
+ prevSep = false
+ j := i + 1
+ level := 0
+ for ; j < len(components); j++ {
+ if components[j].TokenType == css.LeftParenthesisToken {
+ level++
+ } else if components[j].TokenType == css.RightParenthesisToken {
+ if level == 0 {
+ j++
+ break
}
+ level--
}
- if unquote {
- value.Data = s
- }
- }
- } else if prop == css.Outline || prop == css.Border || prop == css.Border_Bottom || prop == css.Border_Left || prop == css.Border_Right || prop == css.Border_Top {
- if css.ToHash(value.Data) == css.None {
- value.TokenType = css.NumberToken
- value.Data = zeroBytes
}
+ values = append(values, Token{components[i].TokenType, components[i].Data, components[i:j]})
+ i = j - 1
+ } else {
+ prevSep = false
+ values = append(values, Token{components[i].TokenType, components[i].Data, nil})
}
- values[i].TokenType, values[i].Data = value.TokenType, value.Data
}
+ c.valuesBuffer = values
- important := false
- if len(values) > 2 && values[len(values)-2].TokenType == css.DelimToken && values[len(values)-2].Data[0] == '!' && css.ToHash(values[len(values)-1].Data) == css.Important {
- values = values[:len(values)-2]
- important = true
- }
+ // Do not process complex values (eg. containing blocks or is not alternated between whitespace/commas and flat values
+ if !simple {
+ if prop == css.Filter && len(components) == 11 {
+ if bytes.Equal(components[0].Data, []byte("progid")) &&
+ components[1].TokenType == css.ColonToken &&
+ bytes.Equal(components[2].Data, []byte("DXImageTransform")) &&
+ components[3].Data[0] == '.' &&
+ bytes.Equal(components[4].Data, []byte("Microsoft")) &&
+ components[5].Data[0] == '.' &&
+ bytes.Equal(components[6].Data, []byte("Alpha(")) &&
+ bytes.Equal(parse.ToLower(components[7].Data), []byte("opacity")) &&
+ components[8].Data[0] == '=' &&
+ components[10].Data[0] == ')' {
+ components = components[6:]
+ components[0].Data = []byte("alpha(")
+ }
+ }
- if len(values) == 1 {
- if prop == css.Background && css.ToHash(values[0].Data) == css.None {
- values[0].Data = backgroundNoneBytes
- } else if bytes.Equal(property, msfilterBytes) {
- alpha := []byte("progid:DXImageTransform.Microsoft.Alpha(Opacity=")
- if values[0].TokenType == css.StringToken && bytes.HasPrefix(values[0].Data[1:len(values[0].Data)-1], alpha) {
- values[0].Data = append(append([]byte{values[0].Data[0]}, []byte("alpha(opacity=")...), values[0].Data[1+len(alpha):]...)
+ for _, component := range components {
+ if _, err := c.w.Write(component.Data); err != nil {
+ return err
}
}
- } else {
- if prop == css.Margin || prop == css.Padding || prop == css.Border_Width {
- if (values[0].TokenType == css.NumberToken || values[0].TokenType == css.DimensionToken || values[0].TokenType == css.PercentageToken) && (len(values)+1)%2 == 0 {
- valid := true
- for i := 1; i < len(values); i += 2 {
- if values[i].TokenType != css.WhitespaceToken || values[i+1].TokenType != css.NumberToken && values[i+1].TokenType != css.DimensionToken && values[i+1].TokenType != css.PercentageToken {
- valid = false
+ if important {
+ if _, err := c.w.Write([]byte("!important")); err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+
+ for i := range values {
+ values[i].TokenType, values[i].Data = c.shortenToken(prop, values[i].TokenType, values[i].Data)
+ }
+
+ if len(values) > 0 {
+ switch prop {
+ case css.Font, css.Font_Weight, css.Font_Family:
+ if prop == css.Font {
+ // in "font:" shorthand all values before the size have "normal"
+ // as valid and, at the same time, default value, so just skip them
+ for i, value := range values {
+ if !(value.TokenType == css.IdentToken && css.ToHash(value.Data) == css.Normal) {
+ values = values[i:]
break
}
}
- if valid {
- n := (len(values) + 1) / 2
- if n == 2 {
- if bytes.Equal(values[0].Data, values[2].Data) {
- values = values[:1]
- }
- } else if n == 3 {
- if bytes.Equal(values[0].Data, values[2].Data) && bytes.Equal(values[0].Data, values[4].Data) {
- values = values[:1]
- } else if bytes.Equal(values[0].Data, values[4].Data) {
- values = values[:3]
- }
- } else if n == 4 {
- if bytes.Equal(values[0].Data, values[2].Data) && bytes.Equal(values[0].Data, values[4].Data) && bytes.Equal(values[0].Data, values[6].Data) {
- values = values[:1]
- } else if bytes.Equal(values[0].Data, values[4].Data) && bytes.Equal(values[2].Data, values[6].Data) {
- values = values[:3]
- } else if bytes.Equal(values[2].Data, values[6].Data) {
- values = values[:5]
+ }
+ for i, value := range values {
+ if value.TokenType == css.IdentToken {
+ val := css.ToHash(value.Data)
+ if prop == css.Font_Weight && val == css.Normal {
+ values[i].TokenType = css.NumberToken
+ values[i].Data = []byte("400")
+ } else if val == css.Bold {
+ values[i].TokenType = css.NumberToken
+ values[i].Data = []byte("700")
+ }
+ } else if value.TokenType == css.StringToken && len(value.Data) > 2 {
+ unquote := true
+ parse.ToLower(value.Data)
+ s := value.Data[1 : len(value.Data)-1]
+ if len(s) > 0 {
+ for _, split := range bytes.Split(s, spaceBytes) {
+ val := css.ToHash(split)
+ // if len is zero, it contains two consecutive spaces
+ if val == css.Inherit || val == css.Serif || val == css.Sans_Serif || val == css.Monospace || val == css.Fantasy || val == css.Cursive || val == css.Initial || val == css.Default ||
+ len(split) == 0 || !css.IsIdent(split) {
+ unquote = false
+ break
+ }
}
}
+ if unquote {
+ values[i].Data = s
+ }
}
}
- } else if prop == css.Filter && len(values) == 11 {
- if bytes.Equal(values[0].Data, []byte("progid")) &&
- values[1].TokenType == css.ColonToken &&
- bytes.Equal(values[2].Data, []byte("DXImageTransform")) &&
- values[3].Data[0] == '.' &&
- bytes.Equal(values[4].Data, []byte("Microsoft")) &&
- values[5].Data[0] == '.' &&
- bytes.Equal(values[6].Data, []byte("Alpha(")) &&
- bytes.Equal(parse.ToLower(values[7].Data), []byte("opacity")) &&
- values[8].Data[0] == '=' &&
- values[10].Data[0] == ')' {
- values = values[6:]
- values[0].Data = []byte("alpha(")
+ case css.Margin, css.Padding, css.Border_Width:
+ n := len(values)
+ if n == 2 {
+ if bytes.Equal(values[0].Data, values[1].Data) {
+ values = values[:1]
+ }
+ } else if n == 3 {
+ if bytes.Equal(values[0].Data, values[1].Data) && bytes.Equal(values[0].Data, values[2].Data) {
+ values = values[:1]
+ } else if bytes.Equal(values[0].Data, values[2].Data) {
+ values = values[:2]
+ }
+ } else if n == 4 {
+ if bytes.Equal(values[0].Data, values[1].Data) && bytes.Equal(values[0].Data, values[2].Data) && bytes.Equal(values[0].Data, values[3].Data) {
+ values = values[:1]
+ } else if bytes.Equal(values[0].Data, values[2].Data) && bytes.Equal(values[1].Data, values[3].Data) {
+ values = values[:2]
+ } else if bytes.Equal(values[1].Data, values[3].Data) {
+ values = values[:3]
+ }
+ }
+ case css.Outline, css.Border, css.Border_Bottom, css.Border_Left, css.Border_Right, css.Border_Top:
+ none := false
+ iZero := -1
+ for i, value := range values {
+ if len(value.Data) == 1 && value.Data[0] == '0' {
+ iZero = i
+ } else if css.ToHash(value.Data) == css.None {
+ values[i].TokenType = css.NumberToken
+ values[i].Data = zeroBytes
+ none = true
+ }
+ }
+ if none && iZero != -1 {
+ values = append(values[:iZero], values[iZero+1:]...)
+ }
+ case css.Background:
+ ident := css.ToHash(values[0].Data)
+ if len(values) == 1 && (ident == css.None || ident == css.Transparent) {
+ values[0].Data = backgroundNoneBytes
+ }
+ case css.Box_Shadow:
+ if len(values) == 4 && len(values[0].Data) == 1 && values[0].Data[0] == '0' && len(values[1].Data) == 1 && values[1].Data[0] == '0' && len(values[2].Data) == 1 && values[2].Data[0] == '0' && len(values[3].Data) == 1 && values[3].Data[0] == '0' {
+ values = values[:2]
+ }
+ default:
+ if bytes.Equal(property, msfilterBytes) {
+ alpha := []byte("progid:DXImageTransform.Microsoft.Alpha(Opacity=")
+ if values[0].TokenType == css.StringToken && bytes.HasPrefix(values[0].Data[1:len(values[0].Data)-1], alpha) {
+ values[0].Data = append(append([]byte{values[0].Data[0]}, []byte("alpha(opacity=")...), values[0].Data[1+len(alpha):]...)
+ }
}
}
}
- for i := 0; i < len(values); i++ {
- if values[i].TokenType == css.FunctionToken {
- n, err := c.minifyFunction(values[i:])
+ prevComma := true
+ for _, value := range values {
+ if !prevComma && value.TokenType != css.CommaToken {
+ if _, err := c.w.Write([]byte(" ")); err != nil {
+ return err
+ }
+ }
+
+ if value.TokenType == css.FunctionToken {
+ err := c.minifyFunction(value.Components)
if err != nil {
return err
}
- i += n - 1
- } else if _, err := c.w.Write(values[i].Data); err != nil {
- return err
+ } else {
+ if _, err := c.w.Write(value.Data); err != nil {
+ return err
+ }
+ }
+
+ if value.TokenType == css.CommaToken {
+ prevComma = true
+ } else {
+ prevComma = false
}
}
+
if important {
if _, err := c.w.Write([]byte("!important")); err != nil {
return err
@@ -356,104 +472,76 @@ func (c *cssMinifier) minifyDeclaration(property []byte, values []css.Token) err
return nil
}
-func (c *cssMinifier) minifyFunction(values []css.Token) (int, error) {
- n := 1
- simple := true
- for i, value := range values[1:] {
- if value.TokenType == css.RightParenthesisToken {
- n++
- break
- }
- if i%2 == 0 && (value.TokenType != css.NumberToken && value.TokenType != css.PercentageToken) || (i%2 == 1 && value.TokenType != css.CommaToken) {
- simple = false
- }
- n++
- }
- values = values[:n]
- if simple && (n-1)%2 == 0 {
- fun := css.ToHash(values[0].Data[:len(values[0].Data)-1])
- nArgs := (n - 1) / 2
- if (fun == css.Rgba || fun == css.Hsla) && nArgs == 4 {
- d, _ := strconv.ParseFloat(string(values[7].Data), 32) // can never fail because if simple == true than this is a NumberToken or PercentageToken
- if d-1.0 > -minify.Epsilon {
- if fun == css.Rgba {
- values[0].Data = []byte("rgb(")
- fun = css.Rgb
- } else {
- values[0].Data = []byte("hsl(")
- fun = css.Hsl
- }
- values = values[:len(values)-2]
- values[len(values)-1].Data = []byte(")")
- nArgs = 3
- } else if d < minify.Epsilon {
- values[0].Data = []byte("transparent")
- values = values[:1]
- fun = 0
- nArgs = 0
+func (c *cssMinifier) minifyFunction(values []css.Token) error {
+ n := len(values)
+ if n > 2 {
+ simple := true
+ for i, value := range values[1 : n-1] {
+ if i%2 == 0 && (value.TokenType != css.NumberToken && value.TokenType != css.PercentageToken) || (i%2 == 1 && value.TokenType != css.CommaToken) {
+ simple = false
}
}
- if fun == css.Rgb && nArgs == 3 {
- var err [3]error
- rgb := [3]byte{}
- for j := 0; j < 3; j++ {
- val := values[j*2+1]
- if val.TokenType == css.NumberToken {
- var d int64
- d, err[j] = strconv.ParseInt(string(val.Data), 10, 32)
- if d < 0 {
- d = 0
- } else if d > 255 {
- d = 255
- }
- rgb[j] = byte(d)
- } else if val.TokenType == css.PercentageToken {
- var d float64
- d, err[j] = strconv.ParseFloat(string(val.Data[:len(val.Data)-1]), 32)
- if d < 0.0 {
- d = 0.0
- } else if d > 100.0 {
- d = 100.0
+
+ if simple && n%2 == 1 {
+ fun := css.ToHash(values[0].Data[0 : len(values[0].Data)-1])
+ for i := 1; i < n; i += 2 {
+ values[i].TokenType, values[i].Data = c.shortenToken(0, values[i].TokenType, values[i].Data)
+ }
+
+ nArgs := (n - 1) / 2
+ if (fun == css.Rgba || fun == css.Hsla) && nArgs == 4 {
+ d, _ := strconv.ParseFloat(string(values[7].Data), 32) // can never fail because if simple == true than this is a NumberToken or PercentageToken
+ if d-1.0 > -minify.Epsilon {
+ if fun == css.Rgba {
+ values[0].Data = []byte("rgb(")
+ fun = css.Rgb
+ } else {
+ values[0].Data = []byte("hsl(")
+ fun = css.Hsl
}
- rgb[j] = byte((d / 100.0 * 255.0) + 0.5)
+ values = values[:len(values)-2]
+ values[len(values)-1].Data = []byte(")")
+ nArgs = 3
+ } else if d < minify.Epsilon {
+ values[0].Data = []byte("transparent")
+ values = values[:1]
+ fun = 0
+ nArgs = 0
}
}
- if err[0] == nil && err[1] == nil && err[2] == nil {
- val := make([]byte, 7)
- val[0] = '#'
- hex.Encode(val[1:], rgb[:])
- parse.ToLower(val)
- if s, ok := ShortenColorHex[string(val)]; ok {
- if _, err := c.w.Write(s); err != nil {
- return 0, err
- }
- } else {
- if len(val) == 7 && val[1] == val[2] && val[3] == val[4] && val[5] == val[6] {
- val[2] = val[3]
- val[3] = val[5]
- val = val[:4]
- }
- if _, err := c.w.Write(val); err != nil {
- return 0, err
+ if fun == css.Rgb && nArgs == 3 {
+ var err [3]error
+ rgb := [3]byte{}
+ for j := 0; j < 3; j++ {
+ val := values[j*2+1]
+ if val.TokenType == css.NumberToken {
+ var d int64
+ d, err[j] = strconv.ParseInt(string(val.Data), 10, 32)
+ if d < 0 {
+ d = 0
+ } else if d > 255 {
+ d = 255
+ }
+ rgb[j] = byte(d)
+ } else if val.TokenType == css.PercentageToken {
+ var d float64
+ d, err[j] = strconv.ParseFloat(string(val.Data[:len(val.Data)-1]), 32)
+ if d < 0.0 {
+ d = 0.0
+ } else if d > 100.0 {
+ d = 100.0
+ }
+ rgb[j] = byte((d / 100.0 * 255.0) + 0.5)
}
}
- return n, nil
- }
- } else if fun == css.Hsl && nArgs == 3 {
- if values[1].TokenType == css.NumberToken && values[3].TokenType == css.PercentageToken && values[5].TokenType == css.PercentageToken {
- h, err1 := strconv.ParseFloat(string(values[1].Data), 32)
- s, err2 := strconv.ParseFloat(string(values[3].Data[:len(values[3].Data)-1]), 32)
- l, err3 := strconv.ParseFloat(string(values[5].Data[:len(values[5].Data)-1]), 32)
- if err1 == nil && err2 == nil && err3 == nil {
- r, g, b := css.HSL2RGB(h/360.0, s/100.0, l/100.0)
- rgb := []byte{byte((r * 255.0) + 0.5), byte((g * 255.0) + 0.5), byte((b * 255.0) + 0.5)}
+ if err[0] == nil && err[1] == nil && err[2] == nil {
val := make([]byte, 7)
val[0] = '#'
hex.Encode(val[1:], rgb[:])
parse.ToLower(val)
if s, ok := ShortenColorHex[string(val)]; ok {
if _, err := c.w.Write(s); err != nil {
- return 0, err
+ return err
}
} else {
if len(val) == 7 && val[1] == val[2] && val[3] == val[4] && val[5] == val[6] {
@@ -462,20 +550,50 @@ func (c *cssMinifier) minifyFunction(values []css.Token) (int, error) {
val = val[:4]
}
if _, err := c.w.Write(val); err != nil {
- return 0, err
+ return err
}
}
- return n, nil
+ return nil
+ }
+ } else if fun == css.Hsl && nArgs == 3 {
+ if values[1].TokenType == css.NumberToken && values[3].TokenType == css.PercentageToken && values[5].TokenType == css.PercentageToken {
+ h, err1 := strconv.ParseFloat(string(values[1].Data), 32)
+ s, err2 := strconv.ParseFloat(string(values[3].Data[:len(values[3].Data)-1]), 32)
+ l, err3 := strconv.ParseFloat(string(values[5].Data[:len(values[5].Data)-1]), 32)
+ if err1 == nil && err2 == nil && err3 == nil {
+ r, g, b := css.HSL2RGB(h/360.0, s/100.0, l/100.0)
+ rgb := []byte{byte((r * 255.0) + 0.5), byte((g * 255.0) + 0.5), byte((b * 255.0) + 0.5)}
+ val := make([]byte, 7)
+ val[0] = '#'
+ hex.Encode(val[1:], rgb[:])
+ parse.ToLower(val)
+ if s, ok := ShortenColorHex[string(val)]; ok {
+ if _, err := c.w.Write(s); err != nil {
+ return err
+ }
+ } else {
+ if len(val) == 7 && val[1] == val[2] && val[3] == val[4] && val[5] == val[6] {
+ val[2] = val[3]
+ val[3] = val[5]
+ val = val[:4]
+ }
+ if _, err := c.w.Write(val); err != nil {
+ return err
+ }
+ }
+ return nil
+ }
}
}
}
}
+
for _, value := range values {
if _, err := c.w.Write(value.Data); err != nil {
- return 0, err
+ return err
}
}
- return n, nil
+ return nil
}
func (c *cssMinifier) shortenToken(prop css.Hash, tt css.TokenType, data []byte) (css.TokenType, []byte) {
@@ -491,11 +609,15 @@ func (c *cssMinifier) shortenToken(prop css.Hash, tt css.TokenType, data []byte)
}
dim := data[n:]
parse.ToLower(dim)
- data = minify.Number(data[:n], c.o.Decimals)
- if tt == css.PercentageToken && (len(data) != 1 || data[0] != '0' || prop == css.Color) {
- data = append(data, '%')
- } else if tt == css.DimensionToken && (len(data) != 1 || data[0] != '0' || requiredDimension[string(dim)]) {
+ if !c.o.KeepCSS2 {
+ data = minify.Number(data[:n], c.o.Decimals)
+ } else {
+ data = minify.Decimal(data[:n], c.o.Decimals) // don't use exponents
+ }
+ if tt == css.DimensionToken && (len(data) != 1 || data[0] != '0' || !optionalZeroDimension[string(dim)] || prop == css.Flex) {
data = append(data, dim...)
+ } else if tt == css.PercentageToken {
+ data = append(data, '%') // TODO: drop percentage for properties that accept <percentage> and <length>
}
} else if tt == css.IdentToken {
//parse.ToLower(data) // TODO: not all identifiers are case-insensitive; all <custom-ident> properties are case-sensitive
@@ -541,7 +663,7 @@ func (c *cssMinifier) shortenToken(prop css.Hash, tt css.TokenType, data []byte)
} else if tt == css.URLToken {
parse.ToLower(data[:3])
if len(data) > 10 {
- uri := data[4 : len(data)-1]
+ uri := parse.TrimWhitespace(data[4 : len(data)-1])
delim := byte('"')
if uri[0] == '\'' || uri[0] == '"' {
delim = uri[0]