From fc37cdedeb9ae13dcdd2f3e9e0341d1b8812a3ea Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 10 Aug 2024 15:06:03 +0900 Subject: [PATCH] vector: reuse previous allocated subpaths Closes #3060 --- vector/path.go | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/vector/path.go b/vector/path.go index 738552227..3146267ac 100644 --- a/vector/path.go +++ b/vector/path.go @@ -65,6 +65,13 @@ type subpath struct { 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 { return len(s.points) } @@ -78,10 +85,12 @@ func (s *subpath) appendPoint(pt point) { panic("vector: a closed subpathment cannot append a new point") } - // Do not add a too close point to the last point. - // This can cause unexpected rendering results. - if lp := s.lastPoint(); abs(lp.x-pt.x) < 1e-2 && abs(lp.y-pt.y) < 1e-2 { - return + if len(s.points) > 0 { + // Do not add a too close point to the last point. + // This can cause unexpected rendering results. + 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) @@ -103,11 +112,26 @@ type Path struct { subpaths []subpath } +// reset resets the path. +// reset doesn't release the allocated memory so that the memory can be reused. func (p *Path) reset() { p.ops = p.ops[: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 { if len(p.subpaths) > 0 || len(p.ops) == 0 { return p.subpaths @@ -117,9 +141,7 @@ func (p *Path) ensureSubpaths() []subpath { for _, op := range p.ops { switch op.typ { case opTypeMoveTo: - p.subpaths = append(p.subpaths, subpath{ - points: []point{op.p1}, - }) + p.appendNewSubpath(op.p1) cur = op.p1 case opTypeLineTo: p.lineTo(op.p1) @@ -194,9 +216,7 @@ func (p *Path) Close() { func (p *Path) lineTo(pt point) { if len(p.subpaths) == 0 || p.subpaths[len(p.subpaths)-1].closed { - p.subpaths = append(p.subpaths, subpath{ - points: []point{pt}, - }) + p.appendNewSubpath(pt) return } p.subpaths[len(p.subpaths)-1].appendPoint(pt)