Exemplo n.º 1
0
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
}
Exemplo n.º 2
0
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
}