git.lucas.co / go_mono
git clone https://git.lucas.co/go_mono.git

commit98f3e4e74d55d70d8a4af9d455b7ddc0ef59f6ca
parentc78039e8ce
authorNigel Tao <nigeltao@golang.org>
date2016-11-06 16:38
vector: make args float32 pairs instead of f32.Vec2.

The f32.Vec2 type doesn't seem worth it.

Change-Id: I021c7e13d7e2dd261334f4aa7e867df4fd8f1c3e
Reviewed-on: https://go-review.googlesource.com/32772
Reviewed-by: David Crawshaw <crawshaw@golang.org>

 vector/acc_test.go        |   6 +-
 vector/raster_fixed.go    |  34 +++++------
 vector/raster_floating.go |  28 +++++----
 vector/vector.go          | 110 +++++++++++++++++------------------
 vector/vector_test.go     | 143 ++++++++++++++++++++++------------------------
 5 files changed, 153 insertions(+), 168 deletions(-)

diff --git a/vector/acc_test.go b/vector/acc_test.go
index 1dce439..0e2ae58 100644
--- a/vector/acc_test.go
+++ b/vector/acc_test.go
@@ -481,11 +481,11 @@ func makeInXxx(height int, useFloatingPointMath bool) *Rasterizer {
 	for _, d := range data {
 		switch d.n {
 		case 0:
-			z.MoveTo(d.p)
+			z.MoveTo(d.px, d.py)
 		case 1:
-			z.LineTo(d.p)
+			z.LineTo(d.px, d.py)
 		case 2:
-			z.QuadTo(d.p, d.q)
+			z.QuadTo(d.px, d.py, d.qx, d.qy)
 		}
 	}
 	return z
diff --git a/vector/raster_fixed.go b/vector/raster_fixed.go
index 086b9fc..ccfa342 100644
--- a/vector/raster_fixed.go
+++ b/vector/raster_fixed.go
@@ -7,10 +7,6 @@ package vector
 // This file contains a fixed point math implementation of the vector
 // graphics rasterizer.
 
-import (
-	"golang.org/x/image/math/f32"
-)
-
 const (
 	// ϕ is the number of binary digits after the fixed point.
 	//
@@ -58,35 +54,35 @@ func fixedMin(x, y int1ϕ) int1ϕ {
 func fixedFloor(x int1ϕ) int32 { return int32(x >> ϕ) }
 func fixedCeil(x int1ϕ) int32  { return int32((x + fxOneMinusIota) >> ϕ) }
 
-func (z *Rasterizer) fixedLineTo(b f32.Vec2) {
-	a := z.pen
-	z.pen = b
+func (z *Rasterizer) fixedLineTo(bx, by float32) {
+	ax, ay := z.penX, z.penY
+	z.penX, z.penY = bx, by
 	dir := int1ϕ(1)
-	if a[1] > b[1] {
-		dir, a, b = -1, b, a
+	if ay > by {
+		dir, ax, ay, bx, by = -1, bx, by, ax, ay
 	}
 	// Horizontal line segments yield no change in coverage. Almost horizontal
 	// segments would yield some change, in ideal math, but the computation
-	// further below, involving 1 / (b[1] - a[1]), is unstable in fixed point
-	// math, so we treat the segment as if it was perfectly horizontal.
-	if b[1]-a[1] <= 0.000001 {
+	// further below, involving 1 / (by - ay), is unstable in fixed point math,
+	// so we treat the segment as if it was perfectly horizontal.
+	if by-ay <= 0.000001 {
 		return
 	}
-	dxdy := (b[0] - a[0]) / (b[1] - a[1])
+	dxdy := (bx - ax) / (by - ay)
 
-	ay := int1ϕ(a[1] * float32(fxOne))
-	by := int1ϕ(b[1] * float32(fxOne))
+	ayϕ := int1ϕ(ay * float32(fxOne))
+	byϕ := int1ϕ(by * float32(fxOne))
 
-	x := int1ϕ(a[0] * float32(fxOne))
-	y := fixedFloor(ay)
-	yMax := fixedCeil(by)
+	x := int1ϕ(ax * float32(fxOne))
+	y := fixedFloor(ayϕ)
+	yMax := fixedCeil(byϕ)
 	if yMax > int32(z.size.Y) {
 		yMax = int32(z.size.Y)
 	}
 	width := int32(z.size.X)
 
 	for ; y < yMax; y++ {
-		dy := fixedMin(int1ϕ(y+1)<<ϕ, by) - fixedMax(int1ϕ(y)<<ϕ, ay)
+		dy := fixedMin(int1ϕ(y+1)<<ϕ, byϕ) - fixedMax(int1ϕ(y)<<ϕ, ayϕ)
 		xNext := x + int1ϕ(float32(dy)*dxdy)
 		if y < 0 {
 			x = xNext
diff --git a/vector/raster_floating.go b/vector/raster_floating.go
index 119845a..143b376 100644
--- a/vector/raster_floating.go
+++ b/vector/raster_floating.go
@@ -9,8 +9,6 @@ package vector
 
 import (
 	"math"
-
-	"golang.org/x/image/math/f32"
 )
 
 func floatingMax(x, y float32) float32 {
@@ -30,32 +28,32 @@ func floatingMin(x, y float32) float32 {
 func floatingFloor(x float32) int32 { return int32(math.Floor(float64(x))) }
 func floatingCeil(x float32) int32  { return int32(math.Ceil(float64(x))) }
 
-func (z *Rasterizer) floatingLineTo(b f32.Vec2) {
-	a := z.pen
-	z.pen = b
+func (z *Rasterizer) floatingLineTo(bx, by float32) {
+	ax, ay := z.penX, z.penY
+	z.penX, z.penY = bx, by
 	dir := float32(1)
-	if a[1] > b[1] {
-		dir, a, b = -1, b, a
+	if ay > by {
+		dir, ax, ay, bx, by = -1, bx, by, ax, ay
 	}
 	// Horizontal line segments yield no change in coverage. Almost horizontal
 	// segments would yield some change, in ideal math, but the computation
-	// further below, involving 1 / (b[1] - a[1]), is unstable in floating
-	// point math, so we treat the segment as if it was perfectly horizontal.
-	if b[1]-a[1] <= 0.000001 {
+	// further below, involving 1 / (by - ay), is unstable in floating point
+	// math, so we treat the segment as if it was perfectly horizontal.
+	if by-ay <= 0.000001 {
 		return
 	}
-	dxdy := (b[0] - a[0]) / (b[1] - a[1])
+	dxdy := (bx - ax) / (by - ay)
 
-	x := a[0]
-	y := floatingFloor(a[1])
-	yMax := floatingCeil(b[1])
+	x := ax
+	y := floatingFloor(ay)
+	yMax := floatingCeil(by)
 	if yMax > int32(z.size.Y) {
 		yMax = int32(z.size.Y)
 	}
 	width := int32(z.size.X)
 
 	for ; y < yMax; y++ {
-		dy := floatingMin(float32(y+1), b[1]) - floatingMax(float32(y), a[1])
+		dy := floatingMin(float32(y+1), by) - floatingMax(float32(y), ay)
 		xNext := x + dy*dxdy
 		if y < 0 {
 			x = xNext
diff --git a/vector/vector.go b/vector/vector.go
index 418a956..852a4f8 100644
--- a/vector/vector.go
+++ b/vector/vector.go
@@ -26,8 +26,6 @@ import (
 	"image/color"
 	"image/draw"
 	"math"
-
-	"golang.org/x/image/math/f32"
 )
 
 // floatingPointMathThreshold is the width or height above which the rasterizer
@@ -50,18 +48,8 @@ import (
 // would still produce acceptable quality, but 512 seems to work.
 const floatingPointMathThreshold = 512
 
-func midPoint(p, q f32.Vec2) f32.Vec2 {
-	return f32.Vec2{
-		(p[0] + q[0]) * 0.5,
-		(p[1] + q[1]) * 0.5,
-	}
-}
-
-func lerp(t float32, p, q f32.Vec2) f32.Vec2 {
-	return f32.Vec2{
-		p[0] + t*(q[0]-p[0]),
-		p[1] + t*(q[1]-p[1]),
-	}
+func lerp(t, px, py, qx, qy float32) (x, y float32) {
+	return px + t*(qx-px), py + t*(qy-py)
 }
 
 func clamp(i, width int32) uint {
@@ -106,9 +94,11 @@ type Rasterizer struct {
 
 	useFloatingPointMath bool
 
-	size  image.Point
-	first f32.Vec2
-	pen   f32.Vec2
+	size   image.Point
+	firstX float32
+	firstY float32
+	penX   float32
+	penY   float32
 
 	// DrawOp is the operator used for the Draw method.
 	//
@@ -124,8 +114,10 @@ type Rasterizer struct {
 // This includes setting z.DrawOp to draw.Over.
 func (z *Rasterizer) Reset(w, h int) {
 	z.size = image.Point{w, h}
-	z.first = f32.Vec2{}
-	z.pen = f32.Vec2{}
+	z.firstX = 0
+	z.firstY = 0
+	z.penX = 0
+	z.penY = 0
 	z.DrawOp = draw.Over
 
 	z.setUseFloatingPointMath(w > floatingPointMathThreshold || h > floatingPointMathThreshold)
@@ -169,63 +161,66 @@ func (z *Rasterizer) Bounds() image.Rectangle {
 
 // Pen returns the location of the path-drawing pen: the last argument to the
 // most recent XxxTo call.
-func (z *Rasterizer) Pen() f32.Vec2 {
-	return z.pen
+func (z *Rasterizer) Pen() (x, y float32) {
+	return z.penX, z.penY
 }
 
 // ClosePath closes the current path.
 func (z *Rasterizer) ClosePath() {
-	z.LineTo(z.first)
+	z.LineTo(z.firstX, z.firstY)
 }
 
-// MoveTo starts a new path and moves the pen to a.
+// MoveTo starts a new path and moves the pen to (ax, ay).
 //
 // The coordinates are allowed to be out of the Rasterizer's bounds.
-func (z *Rasterizer) MoveTo(a f32.Vec2) {
-	z.first = a
-	z.pen = a
+func (z *Rasterizer) MoveTo(ax, ay float32) {
+	z.firstX = ax
+	z.firstY = ay
+	z.penX = ax
+	z.penY = ay
 }
 
-// LineTo adds a line segment, from the pen to b, and moves the pen to b.
+// LineTo adds a line segment, from the pen to (bx, by), and moves the pen to
+// (bx, by).
 //
 // The coordinates are allowed to be out of the Rasterizer's bounds.
-func (z *Rasterizer) LineTo(b f32.Vec2) {
+func (z *Rasterizer) LineTo(bx, by float32) {
 	if z.useFloatingPointMath {
-		z.floatingLineTo(b)
+		z.floatingLineTo(bx, by)
 	} else {
-		z.fixedLineTo(b)
+		z.fixedLineTo(bx, by)
 	}
 }
 
-// QuadTo adds a quadratic Bézier segment, from the pen via b to c, and moves
-// the pen to c.
+// QuadTo adds a quadratic Bézier segment, from the pen via (bx, by) to (cx,
+// cy), and moves the pen to (cx, cy).
 //
 // The coordinates are allowed to be out of the Rasterizer's bounds.
-func (z *Rasterizer) QuadTo(b, c f32.Vec2) {
-	a := z.pen
-	devsq := devSquared(a, b, c)
+func (z *Rasterizer) QuadTo(bx, by, cx, cy float32) {
+	ax, ay := z.penX, z.penY
+	devsq := devSquared(ax, ay, bx, by, cx, cy)
 	if devsq >= 0.333 {
 		const tol = 3
 		n := 1 + int(math.Sqrt(math.Sqrt(tol*float64(devsq))))
 		t, nInv := float32(0), 1/float32(n)
 		for i := 0; i < n-1; i++ {
 			t += nInv
-			ab := lerp(t, a, b)
-			bc := lerp(t, b, c)
-			z.LineTo(lerp(t, ab, bc))
+			abx, aby := lerp(t, ax, ay, bx, by)
+			bcx, bcy := lerp(t, bx, by, cx, cy)
+			z.LineTo(lerp(t, abx, aby, bcx, bcy))
 		}
 	}
-	z.LineTo(c)
+	z.LineTo(cx, cy)
 }
 
-// CubeTo adds a cubic Bézier segment, from the pen via b and c to d, and moves
-// the pen to d.
+// CubeTo adds a cubic Bézier segment, from the pen via (bx, by) and (cx, cy)
+// to (dx, dy), and moves the pen to (dx, dy).
 //
 // The coordinates are allowed to be out of the Rasterizer's bounds.
-func (z *Rasterizer) CubeTo(b, c, d f32.Vec2) {
-	a := z.pen
-	devsq := devSquared(a, b, d)
-	if devsqAlt := devSquared(a, c, d); devsq < devsqAlt {
+func (z *Rasterizer) CubeTo(bx, by, cx, cy, dx, dy float32) {
+	ax, ay := z.penX, z.penY
+	devsq := devSquared(ax, ay, bx, by, dx, dy)
+	if devsqAlt := devSquared(ax, ay, cx, cy, dx, dy); devsq < devsqAlt {
 		devsq = devsqAlt
 	}
 	if devsq >= 0.333 {
@@ -234,19 +229,20 @@ func (z *Rasterizer) CubeTo(b, c, d f32.Vec2) {
 		t, nInv := float32(0), 1/float32(n)
 		for i := 0; i < n-1; i++ {
 			t += nInv
-			ab := lerp(t, a, b)
-			bc := lerp(t, b, c)
-			cd := lerp(t, c, d)
-			abc := lerp(t, ab, bc)
-			bcd := lerp(t, bc, cd)
-			z.LineTo(lerp(t, abc, bcd))
+			abx, aby := lerp(t, ax, ay, bx, by)
+			bcx, bcy := lerp(t, bx, by, cx, cy)
+			cdx, cdy := lerp(t, cx, cy, dx, dy)
+			abcx, abcy := lerp(t, abx, aby, bcx, bcy)
+			bcdx, bcdy := lerp(t, bcx, bcy, cdx, cdy)
+			z.LineTo(lerp(t, abcx, abcy, bcdx, bcdy))
 		}
 	}
-	z.LineTo(d)
+	z.LineTo(dx, dy)
 }
 
-// devSquared returns a measure of how curvy the sequnce a to b to c is. It
-// determines how many line segments will approximate a Bézier curve segment.
+// devSquared returns a measure of how curvy the sequence (ax, ay) to (bx, by)
+// to (cx, cy) is. It determines how many line segments will approximate a
+// Bézier curve segment.
 //
 // http://lists.nongnu.org/archive/html/freetype-devel/2016-08/msg00080.html
 // gives the rationale for this evenly spaced heuristic instead of a recursive
@@ -258,9 +254,9 @@ func (z *Rasterizer) CubeTo(b, c, d f32.Vec2) {
 // Taking a circular arc as a simplifying assumption (ie a spherical cow),
 // where I get n, a recursive approach would get 2^⌈lg n⌉, which, if I haven't
 // made any horrible mistakes, is expected to be 33% more in the limit.
-func devSquared(a, b, c f32.Vec2) float32 {
-	devx := a[0] - 2*b[0] + c[0]
-	devy := a[1] - 2*b[1] + c[1]
+func devSquared(ax, ay, bx, by, cx, cy float32) float32 {
+	devx := ax - 2*bx + cx
+	devy := ay - 2*by + cy
 	return devx*devx + devy*devy
 }
 
diff --git a/vector/vector_test.go b/vector/vector_test.go
index f84d040..f32b992 100644
--- a/vector/vector_test.go
+++ b/vector/vector_test.go
@@ -17,8 +17,6 @@ import (
 	"os"
 	"path/filepath"
 	"testing"
-
-	"golang.org/x/image/math/f32"
 )
 
 // encodePNG is useful for manually debugging the tests.
@@ -35,15 +33,13 @@ func encodePNG(dstFilename string, src image.Image) error {
 	return closeErr
 }
 
-func pointOnCircle(center, radius, index, number int) f32.Vec2 {
+func pointOnCircle(center, radius, index, number int) (x, y float32) {
 	c := float64(center)
 	r := float64(radius)
 	i := float64(index)
 	n := float64(number)
-	return f32.Vec2{
-		float32(c + r*(math.Cos(2*math.Pi*i/n))),
-		float32(c + r*(math.Sin(2*math.Pi*i/n))),
-	}
+	return float32(c + r*(math.Cos(2*math.Pi*i/n))),
+		float32(c + r*(math.Sin(2*math.Pi*i/n)))
 }
 
 func TestRasterizeOutOfBounds(t *testing.T) {
@@ -59,15 +55,15 @@ func TestRasterizeOutOfBounds(t *testing.T) {
 	for i := 0; i < n; i++ {
 		for j := 1; j < n/2; j++ {
 			z.Reset(2*center, 2*center)
-			z.MoveTo(f32.Vec2{1 * center, 1 * center})
+			z.MoveTo(1*center, 1*center)
 			z.LineTo(pointOnCircle(center, radius, i+0, n))
 			z.LineTo(pointOnCircle(center, radius, i+j, n))
 			z.ClosePath()
 
-			z.MoveTo(f32.Vec2{0 * center, 0 * center})
-			z.LineTo(f32.Vec2{0 * center, 2 * center})
-			z.LineTo(f32.Vec2{2 * center, 2 * center})
-			z.LineTo(f32.Vec2{2 * center, 0 * center})
+			z.MoveTo(0*center, 0*center)
+			z.LineTo(0*center, 2*center)
+			z.LineTo(2*center, 2*center)
+			z.LineTo(2*center, 0*center)
 			z.ClosePath()
 
 			dst := image.NewAlpha(z.Bounds())
@@ -91,10 +87,7 @@ func TestRasterizePolygon(t *testing.T) {
 	for radius := 4; radius <= 256; radius *= 2 {
 		for n := 3; n <= 19; n += 4 {
 			z.Reset(2*radius, 2*radius)
-			z.MoveTo(f32.Vec2{
-				float32(2 * radius),
-				float32(1 * radius),
-			})
+			z.MoveTo(float32(2*radius), float32(1*radius))
 			for i := 1; i < n; i++ {
 				z.LineTo(pointOnCircle(radius, radius, i, n))
 			}
@@ -112,10 +105,10 @@ func TestRasterizePolygon(t *testing.T) {
 
 func TestRasterizeAlmostAxisAligned(t *testing.T) {
 	z := NewRasterizer(8, 8)
-	z.MoveTo(f32.Vec2{2, 2})
-	z.LineTo(f32.Vec2{6, math.Nextafter32(2, 0)})
-	z.LineTo(f32.Vec2{6, 6})
-	z.LineTo(f32.Vec2{math.Nextafter32(2, 0), 6})
+	z.MoveTo(2, 2)
+	z.LineTo(6, math.Nextafter32(2, 0))
+	z.LineTo(6, 6)
+	z.LineTo(math.Nextafter32(2, 0), 6)
 	z.ClosePath()
 
 	dst := image.NewAlpha(z.Bounds())
@@ -132,10 +125,10 @@ func TestRasterizeWideAlmostHorizontalLines(t *testing.T) {
 		x := float32(int(1 << i))
 
 		z.Reset(8, 8)
-		z.MoveTo(f32.Vec2{-x, 3})
-		z.LineTo(f32.Vec2{+x, 4})
-		z.LineTo(f32.Vec2{+x, 6})
-		z.LineTo(f32.Vec2{-x, 6})
+		z.MoveTo(-x, 3)
+		z.LineTo(+x, 4)
+		z.LineTo(+x, 6)
+		z.LineTo(-x, 6)
 		z.ClosePath()
 
 		dst := image.NewAlpha(z.Bounds())
@@ -149,9 +142,9 @@ func TestRasterizeWideAlmostHorizontalLines(t *testing.T) {
 
 func TestRasterize30Degrees(t *testing.T) {
 	z := NewRasterizer(8, 8)
-	z.MoveTo(f32.Vec2{4, 4})
-	z.LineTo(f32.Vec2{8, 4})
-	z.LineTo(f32.Vec2{4, 6})
+	z.MoveTo(4, 4)
+	z.LineTo(8, 4)
+	z.LineTo(4, 6)
 	z.ClosePath()
 
 	dst := image.NewAlpha(z.Bounds())
@@ -168,11 +161,11 @@ func TestRasterizeRandomLineTos(t *testing.T) {
 		n, rng := 0, rand.New(rand.NewSource(int64(i)))
 
 		z.Reset(i+2, i+2)
-		z.MoveTo(f32.Vec2{float32(i / 2), float32(i / 2)})
+		z.MoveTo(float32(i/2), float32(i/2))
 		for ; rng.Intn(16) != 0; n++ {
 			x := 1 + rng.Intn(i)
 			y := 1 + rng.Intn(i)
-			z.LineTo(f32.Vec2{float32(x), float32(y)})
+			z.LineTo(float32(x), float32(y))
 		}
 		z.ClosePath()
 
@@ -235,10 +228,10 @@ var basicMask = []byte{
 
 func testBasicPath(t *testing.T, prefix string, dst draw.Image, src image.Image, op draw.Op, want []byte) {
 	z := NewRasterizer(16, 16)
-	z.MoveTo(f32.Vec2{2, 2})
-	z.LineTo(f32.Vec2{8, 2})
-	z.QuadTo(f32.Vec2{14, 2}, f32.Vec2{14, 14})
-	z.CubeTo(f32.Vec2{8, 2}, f32.Vec2{5, 20}, f32.Vec2{2, 8})
+	z.MoveTo(2, 2)
+	z.LineTo(8, 2)
+	z.QuadTo(14, 2, 14, 14)
+	z.CubeTo(8, 2, 5, 20, 2, 8)
 	z.ClosePath()
 
 	z.DrawOp = op
@@ -365,45 +358,47 @@ const (
 
 type benchmarkGlyphDatum struct {
 	// n being 0, 1 or 2 means moveTo, lineTo or quadTo.
-	n uint32
-	p f32.Vec2
-	q f32.Vec2
+	n  uint32
+	px float32
+	py float32
+	qx float32
+	qy float32
 }
 
 // benchmarkGlyphData is the 'a' glyph from the Roboto Regular font, translated
 // so that its top left corner is (0, 0).
 var benchmarkGlyphData = []benchmarkGlyphDatum{
-	{0, f32.Vec2{699, 1102}, f32.Vec2{0, 0}},
-	{2, f32.Vec2{683, 1070}, f32.Vec2{673, 988}},
-	{2, f32.Vec2{544, 1122}, f32.Vec2{365, 1122}},
-	{2, f32.Vec2{205, 1122}, f32.Vec2{102.5, 1031.5}},
-	{2, f32.Vec2{0, 941}, f32.Vec2{0, 802}},
-	{2, f32.Vec2{0, 633}, f32.Vec2{128.5, 539.5}},
-	{2, f32.Vec2{257, 446}, f32.Vec2{490, 446}},
-	{1, f32.Vec2{670, 446}, f32.Vec2{0, 0}},
-	{1, f32.Vec2{670, 361}, f32.Vec2{0, 0}},
-	{2, f32.Vec2{670, 264}, f32.Vec2{612, 206.5}},
-	{2, f32.Vec2{554, 149}, f32.Vec2{441, 149}},
-	{2, f32.Vec2{342, 149}, f32.Vec2{275, 199}},
-	{2, f32.Vec2{208, 249}, f32.Vec2{208, 320}},
-	{1, f32.Vec2{22, 320}, f32.Vec2{0, 0}},
-	{2, f32.Vec2{22, 239}, f32.Vec2{79.5, 163.5}},
-	{2, f32.Vec2{137, 88}, f32.Vec2{235.5, 44}},
-	{2, f32.Vec2{334, 0}, f32.Vec2{452, 0}},
-	{2, f32.Vec2{639, 0}, f32.Vec2{745, 93.5}},
-	{2, f32.Vec2{851, 187}, f32.Vec2{855, 351}},
-	{1, f32.Vec2{855, 849}, f32.Vec2{0, 0}},
-	{2, f32.Vec2{855, 998}, f32.Vec2{893, 1086}},
-	{1, f32.Vec2{893, 1102}, f32.Vec2{0, 0}},
-	{1, f32.Vec2{699, 1102}, f32.Vec2{0, 0}},
-	{0, f32.Vec2{392, 961}, f32.Vec2{0, 0}},
-	{2, f32.Vec2{479, 961}, f32.Vec2{557, 916}},
-	{2, f32.Vec2{635, 871}, f32.Vec2{670, 799}},
-	{1, f32.Vec2{670, 577}, f32.Vec2{0, 0}},
-	{1, f32.Vec2{525, 577}, f32.Vec2{0, 0}},
-	{2, f32.Vec2{185, 577}, f32.Vec2{185, 776}},
-	{2, f32.Vec2{185, 863}, f32.Vec2{243, 912}},
-	{2, f32.Vec2{301, 961}, f32.Vec2{392, 961}},
+	{0, 699, 1102, 0, 0},
+	{2, 683, 1070, 673, 988},
+	{2, 544, 1122, 365, 1122},
+	{2, 205, 1122, 102.5, 1031.5},
+	{2, 0, 941, 0, 802},
+	{2, 0, 633, 128.5, 539.5},
+	{2, 257, 446, 490, 446},
+	{1, 670, 446, 0, 0},
+	{1, 670, 361, 0, 0},
+	{2, 670, 264, 612, 206.5},
+	{2, 554, 149, 441, 149},
+	{2, 342, 149, 275, 199},
+	{2, 208, 249, 208, 320},
+	{1, 22, 320, 0, 0},
+	{2, 22, 239, 79.5, 163.5},
+	{2, 137, 88, 235.5, 44},
+	{2, 334, 0, 452, 0},
+	{2, 639, 0, 745, 93.5},
+	{2, 851, 187, 855, 351},
+	{1, 855, 849, 0, 0},
+	{2, 855, 998, 893, 1086},
+	{1, 893, 1102, 0, 0},
+	{1, 699, 1102, 0, 0},
+	{0, 392, 961, 0, 0},
+	{2, 479, 961, 557, 916},
+	{2, 635, 871, 670, 799},
+	{1, 670, 577, 0, 0},
+	{1, 525, 577, 0, 0},
+	{2, 185, 577, 185, 776},
+	{2, 185, 863, 243, 912},
+	{2, 301, 961, 392, 961},
 }
 
 func scaledBenchmarkGlyphData(height int) (width int, data []benchmarkGlyphDatum) {
@@ -412,10 +407,10 @@ func scaledBenchmarkGlyphData(height int) (width int, data []benchmarkGlyphDatum
 	// Clone the benchmarkGlyphData slice and scale its coordinates.
 	data = append(data, benchmarkGlyphData...)
 	for i := range data {
-		data[i].p[0] *= scale
-		data[i].p[1] *= scale
-		data[i].q[0] *= scale
-		data[i].q[1] *= scale
+		data[i].px *= scale
+		data[i].py *= scale
+		data[i].qx *= scale
+		data[i].qy *= scale
 	}
 
 	return int(math.Ceil(float64(benchmarkGlyphWidth * scale))), data
@@ -457,11 +452,11 @@ func benchGlyph(b *testing.B, colorModel byte, loose bool, height int, op draw.O
 		for _, d := range data {
 			switch d.n {
 			case 0:
-				z.MoveTo(d.p)
+				z.MoveTo(d.px, d.py)
 			case 1:
-				z.LineTo(d.p)
+				z.LineTo(d.px, d.py)
 			case 2:
-				z.QuadTo(d.p, d.q)
+				z.QuadTo(d.px, d.py, d.qx, d.qy)
 			}
 		}
 		z.Draw(dst, bounds, src, image.Point{})