func (c *cssMinifier) minifySelectors(property []byte, values []css.Token) error { inAttr := false isClass := false for _, val := range c.p.Values() { if !inAttr { if val.TokenType == css.IdentToken { if !isClass { parse.ToLower(val.Data) } isClass = false } else if val.TokenType == css.DelimToken && val.Data[0] == '.' { isClass = true } else if val.TokenType == css.LeftBracketToken { inAttr = true } } else { if val.TokenType == css.StringToken && len(val.Data) > 2 { s := val.Data[1 : len(val.Data)-1] if css.IsIdent([]byte(s)) { if _, err := c.w.Write(s); err != nil { return err } continue } } else if val.TokenType == css.RightBracketToken { inAttr = false } } if _, err := c.w.Write(val.Data); err != nil { return err } } return nil }
func (c *cssMinifier) minifyDeclaration(property []byte, values []css.Token) error { if len(values) == 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 } 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 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[i].TokenType, values[i].Data = value.TokenType, value.Data } 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 } 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):]...) } } } 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 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] } } } } } 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(") } } } for i := 0; i < len(values); i++ { if values[i].TokenType == css.FunctionToken { n, err := c.minifyFunction(values[i:]) if err != nil { return err } i += n - 1 } else if _, err := c.w.Write(values[i].Data); err != nil { return err } } if important { if _, err := c.w.Write([]byte("!important")); err != nil { return err } } return nil }