vector: reuse previous allocated subpaths

Closes #3060
This commit is contained in:
Hajime Hoshi 2024-08-10 15:06:03 +09:00
parent 309c886c2e
commit fc37cdedeb

View File

@ -65,6 +65,13 @@ type subpath struct {
closed bool closed bool
} }
// reset resets the subpath.
// reset doesn't release the allocated memory so that the memory can be reused.
func (s *subpath) reset() {
s.points = s.points[:0]
s.closed = false
}
func (s subpath) pointCount() int { func (s subpath) pointCount() int {
return len(s.points) return len(s.points)
} }
@ -78,10 +85,12 @@ func (s *subpath) appendPoint(pt point) {
panic("vector: a closed subpathment cannot append a new point") panic("vector: a closed subpathment cannot append a new point")
} }
// Do not add a too close point to the last point. if len(s.points) > 0 {
// This can cause unexpected rendering results. // Do not add a too close point to the last point.
if lp := s.lastPoint(); abs(lp.x-pt.x) < 1e-2 && abs(lp.y-pt.y) < 1e-2 { // This can cause unexpected rendering results.
return if lp := s.lastPoint(); abs(lp.x-pt.x) < 1e-2 && abs(lp.y-pt.y) < 1e-2 {
return
}
} }
s.points = append(s.points, pt) s.points = append(s.points, pt)
@ -103,11 +112,26 @@ type Path struct {
subpaths []subpath subpaths []subpath
} }
// reset resets the path.
// reset doesn't release the allocated memory so that the memory can be reused.
func (p *Path) reset() { func (p *Path) reset() {
p.ops = p.ops[:0] p.ops = p.ops[:0]
p.subpaths = p.subpaths[:0] p.subpaths = p.subpaths[:0]
} }
func (p *Path) appendNewSubpath(pt point) {
if cap(p.subpaths) > len(p.subpaths) {
// Reuse the last subpath since the last subpath might have an already allocated slice.
p.subpaths = p.subpaths[:len(p.subpaths)+1]
p.subpaths[len(p.subpaths)-1].reset()
p.subpaths[len(p.subpaths)-1].appendPoint(pt)
return
}
p.subpaths = append(p.subpaths, subpath{
points: []point{pt},
})
}
func (p *Path) ensureSubpaths() []subpath { func (p *Path) ensureSubpaths() []subpath {
if len(p.subpaths) > 0 || len(p.ops) == 0 { if len(p.subpaths) > 0 || len(p.ops) == 0 {
return p.subpaths return p.subpaths
@ -117,9 +141,7 @@ func (p *Path) ensureSubpaths() []subpath {
for _, op := range p.ops { for _, op := range p.ops {
switch op.typ { switch op.typ {
case opTypeMoveTo: case opTypeMoveTo:
p.subpaths = append(p.subpaths, subpath{ p.appendNewSubpath(op.p1)
points: []point{op.p1},
})
cur = op.p1 cur = op.p1
case opTypeLineTo: case opTypeLineTo:
p.lineTo(op.p1) p.lineTo(op.p1)
@ -194,9 +216,7 @@ func (p *Path) Close() {
func (p *Path) lineTo(pt point) { func (p *Path) lineTo(pt point) {
if len(p.subpaths) == 0 || p.subpaths[len(p.subpaths)-1].closed { if len(p.subpaths) == 0 || p.subpaths[len(p.subpaths)-1].closed {
p.subpaths = append(p.subpaths, subpath{ p.appendNewSubpath(pt)
points: []point{pt},
})
return return
} }
p.subpaths[len(p.subpaths)-1].appendPoint(pt) p.subpaths[len(p.subpaths)-1].appendPoint(pt)