Skip to content

Commit

Permalink
Bugfix: don't convert polyline/rect/polygon/line to path, which break…
Browse files Browse the repository at this point in the history
… CSS
  • Loading branch information
tdewolff committed Jul 21, 2019
1 parent 303fb6e commit c05f24e
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 152 deletions.
6 changes: 2 additions & 4 deletions svg/buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func (z *TokenBuffer) Shift() *Token {

// Attributes extracts the gives attribute hashes from a tag.
// It returns in the same order pointers to the requested token data or nil.
func (z *TokenBuffer) Attributes(hashes ...svg.Hash) ([]*Token, *Token) {
func (z *TokenBuffer) Attributes(hashes ...svg.Hash) []*Token {
n := 0
for {
if t := z.Peek(n); t.TokenType != xml.AttributeToken {
Expand All @@ -116,15 +116,13 @@ func (z *TokenBuffer) Attributes(hashes ...svg.Hash) ([]*Token, *Token) {
z.attrBuffer[i] = nil
}
}
var replacee *Token
for i := z.pos; i < z.pos+n; i++ {
attr := &z.buf[i]
for j, hash := range hashes {
if hash == attr.Hash {
z.attrBuffer[j] = attr
replacee = attr
}
}
}
return z.attrBuffer, replacee
return z.attrBuffer
}
2 changes: 1 addition & 1 deletion svg/buffer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func TestAttributes(t *testing.T) {
tb := NewTokenBuffer(l)
tb.Shift()
for k := 0; k < 2; k++ { // run twice to ensure similar results
attrs, _ := tb.Attributes(svg.X, svg.Y, svg.Width, svg.Height, svg.Rx, svg.Ry)
attrs := tb.Attributes(svg.X, svg.Y, svg.Width, svg.Height, svg.Rx, svg.Ry)
for i := 0; i < 6; i++ {
test.That(t, attrs[i] != nil, "attr must not be nil")
val := string(attrs[i].AttrVal)
Expand Down
153 changes: 13 additions & 140 deletions svg/svg.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,10 @@ func (o *Minifier) Minify(m *minify.M, w io.Writer, r io.Reader, _ map[string]st
tag = t.Hash
if tag == svg.Metadata {
t.Data = nil
} else if tag == svg.Line {
o.shortenLine(tb, &t, p)
} else if tag == svg.Rect {
o.shortenRect(tb, &t, p)
} else if tag == svg.Polygon || tag == svg.Polyline {
o.shortenPoly(tb, &t, p)
o.shortenRect(tb, &t)
}

if t.Data == nil {
skipTag(tb)
} else if _, err := w.Write(t.Data); err != nil {
Expand Down Expand Up @@ -270,143 +267,19 @@ func (o *Minifier) shortenDimension(b []byte) ([]byte, int) {
return b, 0
}

func (o *Minifier) shortenLine(tb *TokenBuffer, t *Token, p *PathData) {
x1, y1, x2, y2 := zeroBytes, zeroBytes, zeroBytes, zeroBytes
if attrs, replacee := tb.Attributes(svg.X1, svg.Y1, svg.X2, svg.Y2); replacee != nil {
// skip converting to path if any attribute contains dimensions, TODO: convert non-percentage dimensions to px
for _, attr := range attrs {
if attr != nil {
if _, dim := parse.Dimension(attr.AttrVal); dim != 0 {
return
}
}
}

if attrs[0] != nil {
x1 = minify.Number(attrs[0].AttrVal, o.Decimals)
attrs[0].Text = nil
}
if attrs[1] != nil {
y1 = minify.Number(attrs[1].AttrVal, o.Decimals)
attrs[1].Text = nil
}
if attrs[2] != nil {
x2 = minify.Number(attrs[2].AttrVal, o.Decimals)
attrs[2].Text = nil
}
if attrs[3] != nil {
y2 = minify.Number(attrs[3].AttrVal, o.Decimals)
attrs[3].Text = nil
}

d := make([]byte, 0, 5+len(x1)+len(y1)+len(x2)+len(y2))
d = append(d, 'M')
d = append(d, x1...)
d = append(d, ' ')
d = append(d, y1...)
d = append(d, 'L')
d = append(d, x2...)
d = append(d, ' ')
d = append(d, y2...)
d = append(d, 'z')
d = p.ShortenPathData(d)

t.Data = pathBytes
replacee.Text = dBytes
replacee.AttrVal = d
func (o *Minifier) shortenRect(tb *TokenBuffer, t *Token) {
w, h := zeroBytes, zeroBytes
attrs := tb.Attributes(svg.Width, svg.Height)
if attrs[0] != nil {
n, _ := parse.Dimension(attrs[0].AttrVal)
w = minify.Number(attrs[0].AttrVal[:n], o.Decimals)
}
}

func (o *Minifier) shortenRect(tb *TokenBuffer, t *Token, p *PathData) {
if attrs, replacee := tb.Attributes(svg.X, svg.Y, svg.Width, svg.Height, svg.Rx, svg.Ry); replacee != nil && attrs[4] == nil && attrs[5] == nil {
// skip converting to path if any attribute contains dimensions, TODO: convert non-percentage dimensions to px
for _, attr := range attrs {
if attr != nil {
if _, dim := parse.Dimension(attr.AttrVal); dim != 0 {
return
}
}
}

x, y, w, h := zeroBytes, zeroBytes, zeroBytes, zeroBytes
if attrs[0] != nil {
x = minify.Number(attrs[0].AttrVal, o.Decimals)
attrs[0].Text = nil
}
if attrs[1] != nil {
y = minify.Number(attrs[1].AttrVal, o.Decimals)
attrs[1].Text = nil
}
if attrs[2] != nil {
w = minify.Number(attrs[2].AttrVal, o.Decimals)
attrs[2].Text = nil
}
if attrs[3] != nil {
h = minify.Number(attrs[3].AttrVal, o.Decimals)
attrs[3].Text = nil
}
if len(w) == 0 || w[0] == '0' || len(h) == 0 || h[0] == '0' {
t.Data = nil
return
}

d := make([]byte, 0, 6+2*len(x)+len(y)+len(w)+len(h))
d = append(d, 'M')
d = append(d, x...)
d = append(d, ' ')
d = append(d, y...)
d = append(d, 'h')
d = append(d, w...)
d = append(d, 'v')
d = append(d, h...)
d = append(d, 'H')
d = append(d, x...)
d = append(d, 'z')
d = p.ShortenPathData(d)

t.Data = pathBytes
replacee.Text = dBytes
replacee.AttrVal = d
if attrs[1] != nil {
n, _ := parse.Dimension(attrs[1].AttrVal)
h = minify.Number(attrs[1].AttrVal[:n], o.Decimals)
}
}

func (o *Minifier) shortenPoly(tb *TokenBuffer, t *Token, p *PathData) {
if attrs, replacee := tb.Attributes(svg.Points); replacee != nil && attrs[0] != nil {
points := attrs[0].AttrVal

i := 0
for i < len(points) && !(points[i] == ' ' || points[i] == ',' || points[i] == '\n' || points[i] == '\r' || points[i] == '\t') {
i++
}
for i < len(points) && (points[i] == ' ' || points[i] == ',' || points[i] == '\n' || points[i] == '\r' || points[i] == '\t') {
i++
}
for i < len(points) && !(points[i] == ' ' || points[i] == ',' || points[i] == '\n' || points[i] == '\r' || points[i] == '\t') {
i++
}
endMoveTo := i
for i < len(points) && (points[i] == ' ' || points[i] == ',' || points[i] == '\n' || points[i] == '\r' || points[i] == '\t') {
i++
}
startLineTo := i

if i == len(points) {
return
}

d := make([]byte, 0, len(points)+3)
d = append(d, 'M')
d = append(d, points[:endMoveTo]...)
d = append(d, 'L')
d = append(d, points[startLineTo:]...)
if t.Hash == svg.Polygon {
d = append(d, 'z')
}
d = p.ShortenPathData(d)

t.Data = pathBytes
replacee.Text = dBytes
replacee.AttrVal = d
if len(w) == 0 || w[0] == '0' || len(h) == 0 || h[0] == '0' {
t.Data = nil
}
}

Expand Down
9 changes: 2 additions & 7 deletions svg/svg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,10 @@ func TestSVG(t *testing.T) {
{`<path fill="#fff"/>`, `<path fill="#fff"/>`},
{`<path fill="white"/>`, `<path fill="#fff"/>`},
{`<path fill="#ff0000"/>`, `<path fill="red"/>`},
{`<line x1="5" y1="10" x2="20" y2="40"/>`, `<path d="M5 10 20 40z"/>`},
{`<rect x="5" y="10" width="20" height="40"/>`, `<path d="M5 10h20v40H5z"/>`},
{`<rect x="-5.669" y="147.402" fill="#843733" width="252.279" height="14.177"/>`, `<path fill="#843733" d="M-5.669 147.402h252.279v14.177H-5.669z"/>`},
{`<rect x="5" y="10" rx="2" ry="3"/>`, `<rect x="5" y="10" rx="2" ry="3"/>`},
{`<rect x="5" y="10" rx="2" ry="3"/>`, ``},
{`<rect x="5" y="10" height="40"/>`, ``},
{`<rect x="5" y="10" width="30" height="0"/>`, ``},
{`<rect x="5" y="10" width="30" height="0%"/>`, ``},
{`<rect x="5" y="10" width="30%" height="100%"/>`, `<rect x="5" y="10" width="30%" height="100%"/>`},
{`<polygon points="1,2 3,4"/>`, `<path d="M1 2 3 4z"/>`},
{`<polyline points="1,2 3,4"/>`, `<path d="M1 2 3 4"/>`},
{`<svg contentStyleType="text/json ; charset=iso-8859-1"><style>{a : true}</style></svg>`, `<svg contentStyleType="text/json;charset=iso-8859-1"><style>{a : true}</style></svg>`},
{`<metadata><dc:title /></metadata>`, ``},

Expand Down

0 comments on commit c05f24e

Please sign in to comment.