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

vector/vector_test.go (16.7K)

  1 // Copyright 2016 The Go Authors. All rights reserved.
  2 // Use of this source code is governed by a BSD-style
  3 // license that can be found in the LICENSE file.
  4 
  5 package vector
  6 
  7 // TODO: add tests for NaN and Inf coordinates.
  8 
  9 import (
 10 	"fmt"
 11 	"image"
 12 	"image/color"
 13 	"image/draw"
 14 	"image/png"
 15 	"math"
 16 	"math/rand"
 17 	"os"
 18 	"path/filepath"
 19 	"testing"
 20 )
 21 
 22 // encodePNG is useful for manually debugging the tests.
 23 func encodePNG(dstFilename string, src image.Image) error {
 24 	f, err := os.Create(dstFilename)
 25 	if err != nil {
 26 		return err
 27 	}
 28 	encErr := png.Encode(f, src)
 29 	closeErr := f.Close()
 30 	if encErr != nil {
 31 		return encErr
 32 	}
 33 	return closeErr
 34 }
 35 
 36 func pointOnCircle(center, radius, index, number int) (x, y float32) {
 37 	c := float64(center)
 38 	r := float64(radius)
 39 	i := float64(index)
 40 	n := float64(number)
 41 	return float32(c + r*(math.Cos(2*math.Pi*i/n))),
 42 		float32(c + r*(math.Sin(2*math.Pi*i/n)))
 43 }
 44 
 45 func TestRasterizeOutOfBounds(t *testing.T) {
 46 	// Set this to a non-empty string such as "/tmp" to manually inspect the
 47 	// rasterization.
 48 	//
 49 	// If empty, this test simply checks that calling LineTo with points out of
 50 	// the rasterizer's bounds doesn't panic.
 51 	const tmpDir = ""
 52 
 53 	const center, radius, n = 16, 20, 16
 54 	var z Rasterizer
 55 	for i := 0; i < n; i++ {
 56 		for j := 1; j < n/2; j++ {
 57 			z.Reset(2*center, 2*center)
 58 			z.MoveTo(1*center, 1*center)
 59 			z.LineTo(pointOnCircle(center, radius, i+0, n))
 60 			z.LineTo(pointOnCircle(center, radius, i+j, n))
 61 			z.ClosePath()
 62 
 63 			z.MoveTo(0*center, 0*center)
 64 			z.LineTo(0*center, 2*center)
 65 			z.LineTo(2*center, 2*center)
 66 			z.LineTo(2*center, 0*center)
 67 			z.ClosePath()
 68 
 69 			dst := image.NewAlpha(z.Bounds())
 70 			z.Draw(dst, dst.Bounds(), image.Opaque, image.Point{})
 71 
 72 			if tmpDir == "" {
 73 				continue
 74 			}
 75 
 76 			filename := filepath.Join(tmpDir, fmt.Sprintf("out-%02d-%02d.png", i, j))
 77 			if err := encodePNG(filename, dst); err != nil {
 78 				t.Error(err)
 79 			}
 80 			t.Logf("wrote %s", filename)
 81 		}
 82 	}
 83 }
 84 
 85 func TestRasterizePolygon(t *testing.T) {
 86 	var z Rasterizer
 87 	for radius := 4; radius <= 256; radius *= 2 {
 88 		for n := 3; n <= 19; n += 4 {
 89 			z.Reset(2*radius, 2*radius)
 90 			z.MoveTo(float32(2*radius), float32(1*radius))
 91 			for i := 1; i < n; i++ {
 92 				z.LineTo(pointOnCircle(radius, radius, i, n))
 93 			}
 94 			z.ClosePath()
 95 
 96 			dst := image.NewAlpha(z.Bounds())
 97 			z.Draw(dst, dst.Bounds(), image.Opaque, image.Point{})
 98 
 99 			if err := checkCornersCenter(dst); err != nil {
100 				t.Errorf("radius=%d, n=%d: %v", radius, n, err)
101 			}
102 		}
103 	}
104 }
105 
106 func TestRasterizeAlmostAxisAligned(t *testing.T) {
107 	z := NewRasterizer(8, 8)
108 	z.MoveTo(2, 2)
109 	z.LineTo(6, math.Nextafter32(2, 0))
110 	z.LineTo(6, 6)
111 	z.LineTo(math.Nextafter32(2, 0), 6)
112 	z.ClosePath()
113 
114 	dst := image.NewAlpha(z.Bounds())
115 	z.Draw(dst, dst.Bounds(), image.Opaque, image.Point{})
116 
117 	if err := checkCornersCenter(dst); err != nil {
118 		t.Error(err)
119 	}
120 }
121 
122 func TestRasterizeWideAlmostHorizontalLines(t *testing.T) {
123 	var z Rasterizer
124 	for i := uint(3); i < 16; i++ {
125 		x := float32(int(1 << i))
126 
127 		z.Reset(8, 8)
128 		z.MoveTo(-x, 3)
129 		z.LineTo(+x, 4)
130 		z.LineTo(+x, 6)
131 		z.LineTo(-x, 6)
132 		z.ClosePath()
133 
134 		dst := image.NewAlpha(z.Bounds())
135 		z.Draw(dst, dst.Bounds(), image.Opaque, image.Point{})
136 
137 		if err := checkCornersCenter(dst); err != nil {
138 			t.Errorf("i=%d: %v", i, err)
139 		}
140 	}
141 }
142 
143 func TestRasterize30Degrees(t *testing.T) {
144 	z := NewRasterizer(8, 8)
145 	z.MoveTo(4, 4)
146 	z.LineTo(8, 4)
147 	z.LineTo(4, 6)
148 	z.ClosePath()
149 
150 	dst := image.NewAlpha(z.Bounds())
151 	z.Draw(dst, dst.Bounds(), image.Opaque, image.Point{})
152 
153 	if err := checkCornersCenter(dst); err != nil {
154 		t.Error(err)
155 	}
156 }
157 
158 func TestRasterizeRandomLineTos(t *testing.T) {
159 	var z Rasterizer
160 	for i := 5; i < 50; i++ {
161 		n, rng := 0, rand.New(rand.NewSource(int64(i)))
162 
163 		z.Reset(i+2, i+2)
164 		z.MoveTo(float32(i/2), float32(i/2))
165 		for ; rng.Intn(16) != 0; n++ {
166 			x := 1 + rng.Intn(i)
167 			y := 1 + rng.Intn(i)
168 			z.LineTo(float32(x), float32(y))
169 		}
170 		z.ClosePath()
171 
172 		dst := image.NewAlpha(z.Bounds())
173 		z.Draw(dst, dst.Bounds(), image.Opaque, image.Point{})
174 
175 		if err := checkCorners(dst); err != nil {
176 			t.Errorf("i=%d (%d nodes): %v", i, n, err)
177 		}
178 	}
179 }
180 
181 // checkCornersCenter checks that the corners of the image are all 0x00 and the
182 // center is 0xff.
183 func checkCornersCenter(m *image.Alpha) error {
184 	if err := checkCorners(m); err != nil {
185 		return err
186 	}
187 	size := m.Bounds().Size()
188 	center := m.Pix[(size.Y/2)*m.Stride+(size.X/2)]
189 	if center != 0xff {
190 		return fmt.Errorf("center: got %#02x, want 0xff", center)
191 	}
192 	return nil
193 }
194 
195 // checkCorners checks that the corners of the image are all 0x00.
196 func checkCorners(m *image.Alpha) error {
197 	size := m.Bounds().Size()
198 	corners := [4]uint8{
199 		m.Pix[(0*size.Y+0)*m.Stride+(0*size.X+0)],
200 		m.Pix[(0*size.Y+0)*m.Stride+(1*size.X-1)],
201 		m.Pix[(1*size.Y-1)*m.Stride+(0*size.X+0)],
202 		m.Pix[(1*size.Y-1)*m.Stride+(1*size.X-1)],
203 	}
204 	if corners != [4]uint8{} {
205 		return fmt.Errorf("corners were not all zero: %v", corners)
206 	}
207 	return nil
208 }
209 
210 var basicMask = []byte{
211 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
212 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
213 	0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xaa, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
214 	0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x5f, 0x00, 0x00, 0x00, 0x00,
215 	0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x24, 0x00, 0x00, 0x00,
216 	0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa1, 0x00, 0x00, 0x00,
217 	0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x14, 0x00, 0x00,
218 	0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4a, 0x00, 0x00,
219 	0x00, 0x00, 0xcc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0x00, 0x00,
220 	0x00, 0x00, 0x66, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xe4, 0xff, 0xff, 0xff, 0xb6, 0x00, 0x00,
221 	0x00, 0x00, 0x0c, 0xf2, 0xff, 0xff, 0xfe, 0x9e, 0x15, 0x00, 0x15, 0x96, 0xff, 0xce, 0x00, 0x00,
222 	0x00, 0x00, 0x00, 0x88, 0xfc, 0xe3, 0x43, 0x00, 0x00, 0x00, 0x00, 0x06, 0xcd, 0xdc, 0x00, 0x00,
223 	0x00, 0x00, 0x00, 0x00, 0x10, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0xde, 0x00, 0x00,
224 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00,
225 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
226 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227 }
228 
229 func testBasicPath(t *testing.T, prefix string, dst draw.Image, src image.Image, op draw.Op, want []byte) {
230 	z := NewRasterizer(16, 16)
231 	z.MoveTo(2, 2)
232 	z.LineTo(8, 2)
233 	z.QuadTo(14, 2, 14, 14)
234 	z.CubeTo(8, 2, 5, 20, 2, 8)
235 	z.ClosePath()
236 
237 	z.DrawOp = op
238 	z.Draw(dst, z.Bounds(), src, image.Point{})
239 
240 	var got []byte
241 	switch dst := dst.(type) {
242 	case *image.Alpha:
243 		got = dst.Pix
244 	case *image.RGBA:
245 		got = dst.Pix
246 	default:
247 		t.Errorf("%s: unrecognized dst image type %T", prefix, dst)
248 	}
249 
250 	if len(got) != len(want) {
251 		t.Errorf("%s: len(got)=%d and len(want)=%d differ", prefix, len(got), len(want))
252 		return
253 	}
254 	for i := range got {
255 		delta := int(got[i]) - int(want[i])
256 		// The +/- 2 allows different implementations to give different
257 		// rounding errors.
258 		if delta < -2 || +2 < delta {
259 			t.Errorf("%s: i=%d: got %#02x, want %#02x", prefix, i, got[i], want[i])
260 			return
261 		}
262 	}
263 }
264 
265 func TestBasicPathDstAlpha(t *testing.T) {
266 	for _, background := range []uint8{0x00, 0x80} {
267 		for _, op := range []draw.Op{draw.Over, draw.Src} {
268 			for _, xPadding := range []int{0, 7} {
269 				bounds := image.Rect(0, 0, 16+xPadding, 16)
270 				dst := image.NewAlpha(bounds)
271 				for i := range dst.Pix {
272 					dst.Pix[i] = background
273 				}
274 
275 				want := make([]byte, len(dst.Pix))
276 				copy(want, dst.Pix)
277 
278 				if op == draw.Over && background == 0x80 {
279 					for y := 0; y < 16; y++ {
280 						for x := 0; x < 16; x++ {
281 							ma := basicMask[16*y+x]
282 							i := dst.PixOffset(x, y)
283 							want[i] = 0xff - (0xff-ma)/2
284 						}
285 					}
286 				} else {
287 					for y := 0; y < 16; y++ {
288 						for x := 0; x < 16; x++ {
289 							ma := basicMask[16*y+x]
290 							i := dst.PixOffset(x, y)
291 							want[i] = ma
292 						}
293 					}
294 				}
295 
296 				prefix := fmt.Sprintf("background=%#02x, op=%v, xPadding=%d", background, op, xPadding)
297 				testBasicPath(t, prefix, dst, image.Opaque, op, want)
298 			}
299 		}
300 	}
301 }
302 
303 func TestBasicPathDstRGBA(t *testing.T) {
304 	blue := image.NewUniform(color.RGBA{0x00, 0x00, 0xff, 0xff})
305 
306 	for _, op := range []draw.Op{draw.Over, draw.Src} {
307 		for _, xPadding := range []int{0, 7} {
308 			bounds := image.Rect(0, 0, 16+xPadding, 16)
309 			dst := image.NewRGBA(bounds)
310 			for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
311 				for x := bounds.Min.X; x < bounds.Max.X; x++ {
312 					dst.SetRGBA(x, y, color.RGBA{
313 						R: uint8(y * 0x07),
314 						G: uint8(x * 0x05),
315 						B: 0x00,
316 						A: 0x80,
317 					})
318 				}
319 			}
320 
321 			want := make([]byte, len(dst.Pix))
322 			copy(want, dst.Pix)
323 
324 			if op == draw.Over {
325 				for y := 0; y < 16; y++ {
326 					for x := 0; x < 16; x++ {
327 						ma := basicMask[16*y+x]
328 						i := dst.PixOffset(x, y)
329 						want[i+0] = uint8((uint32(0xff-ma) * uint32(y*0x07)) / 0xff)
330 						want[i+1] = uint8((uint32(0xff-ma) * uint32(x*0x05)) / 0xff)
331 						want[i+2] = ma
332 						want[i+3] = ma/2 + 0x80
333 					}
334 				}
335 			} else {
336 				for y := 0; y < 16; y++ {
337 					for x := 0; x < 16; x++ {
338 						ma := basicMask[16*y+x]
339 						i := dst.PixOffset(x, y)
340 						want[i+0] = 0x00
341 						want[i+1] = 0x00
342 						want[i+2] = ma
343 						want[i+3] = ma
344 					}
345 				}
346 			}
347 
348 			prefix := fmt.Sprintf("op=%v, xPadding=%d", op, xPadding)
349 			testBasicPath(t, prefix, dst, blue, op, want)
350 		}
351 	}
352 }
353 
354 const (
355 	benchmarkGlyphWidth  = 893
356 	benchmarkGlyphHeight = 1122
357 )
358 
359 type benchmarkGlyphDatum struct {
360 	// n being 0, 1 or 2 means moveTo, lineTo or quadTo.
361 	n  uint32
362 	px float32
363 	py float32
364 	qx float32
365 	qy float32
366 }
367 
368 // benchmarkGlyphData is the 'a' glyph from the Roboto Regular font, translated
369 // so that its top left corner is (0, 0).
370 var benchmarkGlyphData = []benchmarkGlyphDatum{
371 	{0, 699, 1102, 0, 0},
372 	{2, 683, 1070, 673, 988},
373 	{2, 544, 1122, 365, 1122},
374 	{2, 205, 1122, 102.5, 1031.5},
375 	{2, 0, 941, 0, 802},
376 	{2, 0, 633, 128.5, 539.5},
377 	{2, 257, 446, 490, 446},
378 	{1, 670, 446, 0, 0},
379 	{1, 670, 361, 0, 0},
380 	{2, 670, 264, 612, 206.5},
381 	{2, 554, 149, 441, 149},
382 	{2, 342, 149, 275, 199},
383 	{2, 208, 249, 208, 320},
384 	{1, 22, 320, 0, 0},
385 	{2, 22, 239, 79.5, 163.5},
386 	{2, 137, 88, 235.5, 44},
387 	{2, 334, 0, 452, 0},
388 	{2, 639, 0, 745, 93.5},
389 	{2, 851, 187, 855, 351},
390 	{1, 855, 849, 0, 0},
391 	{2, 855, 998, 893, 1086},
392 	{1, 893, 1102, 0, 0},
393 	{1, 699, 1102, 0, 0},
394 	{0, 392, 961, 0, 0},
395 	{2, 479, 961, 557, 916},
396 	{2, 635, 871, 670, 799},
397 	{1, 670, 577, 0, 0},
398 	{1, 525, 577, 0, 0},
399 	{2, 185, 577, 185, 776},
400 	{2, 185, 863, 243, 912},
401 	{2, 301, 961, 392, 961},
402 }
403 
404 func scaledBenchmarkGlyphData(height int) (width int, data []benchmarkGlyphDatum) {
405 	scale := float32(height) / benchmarkGlyphHeight
406 
407 	// Clone the benchmarkGlyphData slice and scale its coordinates.
408 	data = append(data, benchmarkGlyphData...)
409 	for i := range data {
410 		data[i].px *= scale
411 		data[i].py *= scale
412 		data[i].qx *= scale
413 		data[i].qy *= scale
414 	}
415 
416 	return int(math.Ceil(float64(benchmarkGlyphWidth * scale))), data
417 }
418 
419 // benchGlyph benchmarks rasterizing a TrueType glyph.
420 //
421 // Note that, compared to the github.com/google/font-go prototype, the height
422 // here is the height of the bounding box, not the pixels per em used to scale
423 // a glyph's vectors. A height of 64 corresponds to a ppem greater than 64.
424 func benchGlyph(b *testing.B, colorModel byte, loose bool, height int, op draw.Op) {
425 	width, data := scaledBenchmarkGlyphData(height)
426 	z := NewRasterizer(width, height)
427 
428 	bounds := z.Bounds()
429 	if loose {
430 		bounds.Max.X++
431 	}
432 	dst, src := draw.Image(nil), image.Image(nil)
433 	switch colorModel {
434 	case 'A':
435 		dst = image.NewAlpha(bounds)
436 		src = image.Opaque
437 	case 'N':
438 		dst = image.NewNRGBA(bounds)
439 		src = image.NewUniform(color.NRGBA{0x40, 0x80, 0xc0, 0xff})
440 	case 'R':
441 		dst = image.NewRGBA(bounds)
442 		src = image.NewUniform(color.RGBA{0x40, 0x80, 0xc0, 0xff})
443 	default:
444 		b.Fatal("unsupported color model")
445 	}
446 	bounds = z.Bounds()
447 
448 	b.ResetTimer()
449 	for i := 0; i < b.N; i++ {
450 		z.Reset(width, height)
451 		z.DrawOp = op
452 		for _, d := range data {
453 			switch d.n {
454 			case 0:
455 				z.MoveTo(d.px, d.py)
456 			case 1:
457 				z.LineTo(d.px, d.py)
458 			case 2:
459 				z.QuadTo(d.px, d.py, d.qx, d.qy)
460 			}
461 		}
462 		z.Draw(dst, bounds, src, image.Point{})
463 	}
464 }
465 
466 // The heights 16, 32, 64, 128, 256, 1024 include numbers both above and below
467 // the floatingPointMathThreshold constant (512).
468 
469 func BenchmarkGlyphAlpha16Over(b *testing.B)   { benchGlyph(b, 'A', false, 16, draw.Over) }
470 func BenchmarkGlyphAlpha16Src(b *testing.B)    { benchGlyph(b, 'A', false, 16, draw.Src) }
471 func BenchmarkGlyphAlpha32Over(b *testing.B)   { benchGlyph(b, 'A', false, 32, draw.Over) }
472 func BenchmarkGlyphAlpha32Src(b *testing.B)    { benchGlyph(b, 'A', false, 32, draw.Src) }
473 func BenchmarkGlyphAlpha64Over(b *testing.B)   { benchGlyph(b, 'A', false, 64, draw.Over) }
474 func BenchmarkGlyphAlpha64Src(b *testing.B)    { benchGlyph(b, 'A', false, 64, draw.Src) }
475 func BenchmarkGlyphAlpha128Over(b *testing.B)  { benchGlyph(b, 'A', false, 128, draw.Over) }
476 func BenchmarkGlyphAlpha128Src(b *testing.B)   { benchGlyph(b, 'A', false, 128, draw.Src) }
477 func BenchmarkGlyphAlpha256Over(b *testing.B)  { benchGlyph(b, 'A', false, 256, draw.Over) }
478 func BenchmarkGlyphAlpha256Src(b *testing.B)   { benchGlyph(b, 'A', false, 256, draw.Src) }
479 func BenchmarkGlyphAlpha1024Over(b *testing.B) { benchGlyph(b, 'A', false, 1024, draw.Over) }
480 func BenchmarkGlyphAlpha1024Src(b *testing.B)  { benchGlyph(b, 'A', false, 1024, draw.Src) }
481 
482 func BenchmarkGlyphAlphaLoose16Over(b *testing.B)   { benchGlyph(b, 'A', true, 16, draw.Over) }
483 func BenchmarkGlyphAlphaLoose16Src(b *testing.B)    { benchGlyph(b, 'A', true, 16, draw.Src) }
484 func BenchmarkGlyphAlphaLoose32Over(b *testing.B)   { benchGlyph(b, 'A', true, 32, draw.Over) }
485 func BenchmarkGlyphAlphaLoose32Src(b *testing.B)    { benchGlyph(b, 'A', true, 32, draw.Src) }
486 func BenchmarkGlyphAlphaLoose64Over(b *testing.B)   { benchGlyph(b, 'A', true, 64, draw.Over) }
487 func BenchmarkGlyphAlphaLoose64Src(b *testing.B)    { benchGlyph(b, 'A', true, 64, draw.Src) }
488 func BenchmarkGlyphAlphaLoose128Over(b *testing.B)  { benchGlyph(b, 'A', true, 128, draw.Over) }
489 func BenchmarkGlyphAlphaLoose128Src(b *testing.B)   { benchGlyph(b, 'A', true, 128, draw.Src) }
490 func BenchmarkGlyphAlphaLoose256Over(b *testing.B)  { benchGlyph(b, 'A', true, 256, draw.Over) }
491 func BenchmarkGlyphAlphaLoose256Src(b *testing.B)   { benchGlyph(b, 'A', true, 256, draw.Src) }
492 func BenchmarkGlyphAlphaLoose1024Over(b *testing.B) { benchGlyph(b, 'A', true, 1024, draw.Over) }
493 func BenchmarkGlyphAlphaLoose1024Src(b *testing.B)  { benchGlyph(b, 'A', true, 1024, draw.Src) }
494 
495 func BenchmarkGlyphRGBA16Over(b *testing.B)   { benchGlyph(b, 'R', false, 16, draw.Over) }
496 func BenchmarkGlyphRGBA16Src(b *testing.B)    { benchGlyph(b, 'R', false, 16, draw.Src) }
497 func BenchmarkGlyphRGBA32Over(b *testing.B)   { benchGlyph(b, 'R', false, 32, draw.Over) }
498 func BenchmarkGlyphRGBA32Src(b *testing.B)    { benchGlyph(b, 'R', false, 32, draw.Src) }
499 func BenchmarkGlyphRGBA64Over(b *testing.B)   { benchGlyph(b, 'R', false, 64, draw.Over) }
500 func BenchmarkGlyphRGBA64Src(b *testing.B)    { benchGlyph(b, 'R', false, 64, draw.Src) }
501 func BenchmarkGlyphRGBA128Over(b *testing.B)  { benchGlyph(b, 'R', false, 128, draw.Over) }
502 func BenchmarkGlyphRGBA128Src(b *testing.B)   { benchGlyph(b, 'R', false, 128, draw.Src) }
503 func BenchmarkGlyphRGBA256Over(b *testing.B)  { benchGlyph(b, 'R', false, 256, draw.Over) }
504 func BenchmarkGlyphRGBA256Src(b *testing.B)   { benchGlyph(b, 'R', false, 256, draw.Src) }
505 func BenchmarkGlyphRGBA1024Over(b *testing.B) { benchGlyph(b, 'R', false, 1024, draw.Over) }
506 func BenchmarkGlyphRGBA1024Src(b *testing.B)  { benchGlyph(b, 'R', false, 1024, draw.Src) }
507 
508 func BenchmarkGlyphNRGBA16Over(b *testing.B)   { benchGlyph(b, 'N', false, 16, draw.Over) }
509 func BenchmarkGlyphNRGBA16Src(b *testing.B)    { benchGlyph(b, 'N', false, 16, draw.Src) }
510 func BenchmarkGlyphNRGBA32Over(b *testing.B)   { benchGlyph(b, 'N', false, 32, draw.Over) }
511 func BenchmarkGlyphNRGBA32Src(b *testing.B)    { benchGlyph(b, 'N', false, 32, draw.Src) }
512 func BenchmarkGlyphNRGBA64Over(b *testing.B)   { benchGlyph(b, 'N', false, 64, draw.Over) }
513 func BenchmarkGlyphNRGBA64Src(b *testing.B)    { benchGlyph(b, 'N', false, 64, draw.Src) }
514 func BenchmarkGlyphNRGBA128Over(b *testing.B)  { benchGlyph(b, 'N', false, 128, draw.Over) }
515 func BenchmarkGlyphNRGBA128Src(b *testing.B)   { benchGlyph(b, 'N', false, 128, draw.Src) }
516 func BenchmarkGlyphNRGBA256Over(b *testing.B)  { benchGlyph(b, 'N', false, 256, draw.Over) }
517 func BenchmarkGlyphNRGBA256Src(b *testing.B)   { benchGlyph(b, 'N', false, 256, draw.Src) }
518 func BenchmarkGlyphNRGBA1024Over(b *testing.B) { benchGlyph(b, 'N', false, 1024, draw.Over) }
519 func BenchmarkGlyphNRGBA1024Src(b *testing.B)  { benchGlyph(b, 'N', false, 1024, draw.Src) }