diff --git a/internal/rendertest/bench_test.go b/internal/rendertest/bench_test.go index fbed640b..2d3499cc 100644 --- a/internal/rendertest/bench_test.go +++ b/internal/rendertest/bench_test.go @@ -97,6 +97,29 @@ func BenchmarkDrawUI(b *testing.B) { finishBenchmark(b, w) } +func BenchmarkDrawUITransformed(b *testing.B) { + // Like BenchmarkDraw UI but transformed at every frame + gtx, w, th := setupBenchmark(b) + drawCore(gtx, th) + w.Frame(gtx.Ops) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + resetOps(gtx) + + p := op.Push(gtx.Ops) + angle := float32(math.Mod(float64(i)/1000, 0.05)) + a := f32.Affine2D{}.Shear(f32.Point{}, angle, angle).Rotate(f32.Point{}, angle) + op.Affine(a).Add(gtx.Ops) + + drawCore(gtx, th) + + p.Pop() + w.Frame(gtx.Ops) + } + finishBenchmark(b, w) +} + func Benchmark1000Circles(b *testing.B) { // Benchmark1000Shapes draws 1000 individual shapes such that no caching between // shapes will be possible and resets buffers on each operation to prevent caching diff --git a/internal/rendertest/clip_test.go b/internal/rendertest/clip_test.go new file mode 100644 index 00000000..fa8f285f --- /dev/null +++ b/internal/rendertest/clip_test.go @@ -0,0 +1,73 @@ +package rendertest + +import ( + "testing" + + "gioui.org/f32" + "gioui.org/op" + "gioui.org/op/clip" + "gioui.org/op/paint" + "golang.org/x/image/colornames" +) + +func TestPaintRect(t *testing.T) { + run(t, func(o *op.Ops) { + paint.ColorOp{Color: colornames.Red}.Add(o) + paint.PaintOp{Rect: f32.Rect(0, 0, 50, 50)}.Add(o) + }, func(r result) { + r.expect(0, 0, colornames.Red) + r.expect(49, 0, colornames.Red) + r.expect(50, 0, colornames.White) + r.expect(10, 50, colornames.White) + }) +} + +func TestPaintClippedRect(t *testing.T) { + run(t, func(o *op.Ops) { + paint.ColorOp{Color: colornames.Red}.Add(o) + clip.Rect{Rect: f32.Rect(25, 25, 60, 60)}.Add(o) + paint.PaintOp{Rect: f32.Rect(0, 0, 50, 50)}.Add(o) + }, func(r result) { + r.expect(0, 0, colornames.White) + r.expect(24, 35, colornames.White) + r.expect(25, 35, colornames.Red) + r.expect(50, 0, colornames.White) + r.expect(10, 50, colornames.White) + }) +} + +func TestPaintClippedCirle(t *testing.T) { + run(t, func(o *op.Ops) { + paint.ColorOp{Color: colornames.Red}.Add(o) + r := float32(10) + clip.Rect{Rect: f32.Rect(20, 20, 40, 40), SE: r, SW: r, NW: r, NE: r}.Add(o) + paint.PaintOp{Rect: f32.Rect(0, 0, 30, 50)}.Add(o) + }, func(r result) { + r.expect(21, 21, colornames.White) + r.expect(25, 30, colornames.Red) + r.expect(31, 30, colornames.White) + }) +} + +func TestPaintTexture(t *testing.T) { + run(t, func(o *op.Ops) { + squares.Add(o) + paint.PaintOp{Rect: f32.Rect(0, 0, 80, 80)}.Add(o) + }, func(r result) { + r.expect(0, 0, colornames.Blue) + r.expect(79, 10, colornames.Green) + r.expect(80, 0, colornames.White) + r.expect(10, 80, colornames.White) + }) +} + +func TestPaintClippedTexture(t *testing.T) { + run(t, func(o *op.Ops) { + squares.Add(o) + clip.Rect{Rect: f32.Rect(0, 0, 40, 40)}.Add(o) + paint.PaintOp{Rect: f32.Rect(0, 0, 80, 80)}.Add(o) + }, func(r result) { + r.expect(40, 40, colornames.White) + r.expect(25, 35, colornames.Blue) + }) +} diff --git a/internal/rendertest/doc.go b/internal/rendertest/doc.go new file mode 100644 index 00000000..9f6948e9 --- /dev/null +++ b/internal/rendertest/doc.go @@ -0,0 +1,2 @@ +// Package rendertest is intended for testing of drawing ops only. +package rendertest diff --git a/internal/rendertest/refs/TestClipOffset.png b/internal/rendertest/refs/TestClipOffset.png new file mode 100644 index 00000000..59371e42 Binary files /dev/null and b/internal/rendertest/refs/TestClipOffset.png differ diff --git a/internal/rendertest/refs/TestClipPaintOffset.png b/internal/rendertest/refs/TestClipPaintOffset.png new file mode 100644 index 00000000..f9988440 Binary files /dev/null and b/internal/rendertest/refs/TestClipPaintOffset.png differ diff --git a/internal/rendertest/refs/TestClipRotate.png b/internal/rendertest/refs/TestClipRotate.png new file mode 100644 index 00000000..e6c0e4e5 Binary files /dev/null and b/internal/rendertest/refs/TestClipRotate.png differ diff --git a/internal/rendertest/refs/TestClipScale.png b/internal/rendertest/refs/TestClipScale.png new file mode 100644 index 00000000..59371e42 Binary files /dev/null and b/internal/rendertest/refs/TestClipScale.png differ diff --git a/internal/rendertest/refs/TestComplicatedTransform.png b/internal/rendertest/refs/TestComplicatedTransform.png new file mode 100644 index 00000000..33042c5e Binary files /dev/null and b/internal/rendertest/refs/TestComplicatedTransform.png differ diff --git a/internal/rendertest/refs/TestNoClipFromPaint.png b/internal/rendertest/refs/TestNoClipFromPaint.png new file mode 100644 index 00000000..b382f873 Binary files /dev/null and b/internal/rendertest/refs/TestNoClipFromPaint.png differ diff --git a/internal/rendertest/refs/TestOffsetScaleTexture.png b/internal/rendertest/refs/TestOffsetScaleTexture.png new file mode 100644 index 00000000..42ebc4bc Binary files /dev/null and b/internal/rendertest/refs/TestOffsetScaleTexture.png differ diff --git a/internal/rendertest/refs/TestOffsetTexture.png b/internal/rendertest/refs/TestOffsetTexture.png new file mode 100644 index 00000000..7f9f029d Binary files /dev/null and b/internal/rendertest/refs/TestOffsetTexture.png differ diff --git a/internal/rendertest/refs/TestPaintClippedCirle.png b/internal/rendertest/refs/TestPaintClippedCirle.png new file mode 100644 index 00000000..9aa298e9 Binary files /dev/null and b/internal/rendertest/refs/TestPaintClippedCirle.png differ diff --git a/internal/rendertest/refs/TestPaintClippedRect.png b/internal/rendertest/refs/TestPaintClippedRect.png new file mode 100644 index 00000000..4bd3e5cb Binary files /dev/null and b/internal/rendertest/refs/TestPaintClippedRect.png differ diff --git a/internal/rendertest/refs/TestPaintClippedTexture.png b/internal/rendertest/refs/TestPaintClippedTexture.png new file mode 100644 index 00000000..ee95e5b8 Binary files /dev/null and b/internal/rendertest/refs/TestPaintClippedTexture.png differ diff --git a/internal/rendertest/refs/TestPaintOffset.png b/internal/rendertest/refs/TestPaintOffset.png new file mode 100644 index 00000000..aa5d7d8f Binary files /dev/null and b/internal/rendertest/refs/TestPaintOffset.png differ diff --git a/internal/rendertest/refs/TestPaintRect.png b/internal/rendertest/refs/TestPaintRect.png new file mode 100644 index 00000000..0195a6be Binary files /dev/null and b/internal/rendertest/refs/TestPaintRect.png differ diff --git a/internal/rendertest/refs/TestPaintRotate.png b/internal/rendertest/refs/TestPaintRotate.png new file mode 100644 index 00000000..4cf9c851 Binary files /dev/null and b/internal/rendertest/refs/TestPaintRotate.png differ diff --git a/internal/rendertest/refs/TestPaintShear.png b/internal/rendertest/refs/TestPaintShear.png new file mode 100644 index 00000000..0a7d553c Binary files /dev/null and b/internal/rendertest/refs/TestPaintShear.png differ diff --git a/internal/rendertest/refs/TestPaintTexture.png b/internal/rendertest/refs/TestPaintTexture.png new file mode 100644 index 00000000..33feacd3 Binary files /dev/null and b/internal/rendertest/refs/TestPaintTexture.png differ diff --git a/internal/rendertest/refs/TestRepeatedPaintsZ.png b/internal/rendertest/refs/TestRepeatedPaintsZ.png new file mode 100644 index 00000000..1da62245 Binary files /dev/null and b/internal/rendertest/refs/TestRepeatedPaintsZ.png differ diff --git a/internal/rendertest/refs/TestReuseStencil.png b/internal/rendertest/refs/TestReuseStencil.png new file mode 100644 index 00000000..7ea05a00 Binary files /dev/null and b/internal/rendertest/refs/TestReuseStencil.png differ diff --git a/internal/rendertest/refs/TestRotateClipTexture.png b/internal/rendertest/refs/TestRotateClipTexture.png new file mode 100644 index 00000000..8cd211d4 Binary files /dev/null and b/internal/rendertest/refs/TestRotateClipTexture.png differ diff --git a/internal/rendertest/refs/TestRotateTexture.png b/internal/rendertest/refs/TestRotateTexture.png new file mode 100644 index 00000000..874e8384 Binary files /dev/null and b/internal/rendertest/refs/TestRotateTexture.png differ diff --git a/internal/rendertest/refs/TestTransformMacro.png b/internal/rendertest/refs/TestTransformMacro.png new file mode 100644 index 00000000..07570593 Binary files /dev/null and b/internal/rendertest/refs/TestTransformMacro.png differ diff --git a/internal/rendertest/refs/TestTransformOrder.png b/internal/rendertest/refs/TestTransformOrder.png new file mode 100644 index 00000000..27c91fb0 Binary files /dev/null and b/internal/rendertest/refs/TestTransformOrder.png differ diff --git a/internal/rendertest/render_test.go b/internal/rendertest/render_test.go new file mode 100644 index 00000000..fe0e78be --- /dev/null +++ b/internal/rendertest/render_test.go @@ -0,0 +1,144 @@ +package rendertest + +import ( + "math" + "testing" + + "gioui.org/f32" + "gioui.org/op" + "gioui.org/op/clip" + "gioui.org/op/paint" + "golang.org/x/image/colornames" +) + +func TestTransformMacro(t *testing.T) { + // testcase resulting from original bug when rendering layout.Stacked + + // pre-build the text + c := createText() + + run(t, func(o *op.Ops) { + + // render the first Stacked item + m1 := op.Record(o) + dr := f32.Rect(0, 0, 128, 50) + paint.ColorOp{Color: colornames.Black}.Add(o) + paint.PaintOp{Rect: dr}.Add(o) + c1 := m1.Stop() + + // Render the second stacked item + m2 := op.Record(o) + paint.ColorOp{Color: colornames.Red}.Add(o) + // Simulate a draw text call + stack := op.Push(o) + op.TransformOp{}.Offset(f32.Pt(0, 10)).Add(o) + + // Actually create the text clip-path + c.Add(o) + + paint.PaintOp{Rect: f32.Rect(0, 0, 10, 10)}.Add(o) + stack.Pop() + + c2 := m2.Stop() + + // Call each of them in a transform + s1 := op.Push(o) + op.TransformOp{}.Offset(f32.Pt(0, 0)).Add(o) + c1.Add(o) + s1.Pop() + s2 := op.Push(o) + op.TransformOp{}.Offset(f32.Pt(0, 0)).Add(o) + c2.Add(o) + s2.Pop() + }, func(r result) { + r.expect(5, 15, colornames.Red) + r.expect(15, 15, colornames.Black) + r.expect(11, 51, colornames.White) + }) +} + +func TestRepeatedPaintsZ(t *testing.T) { + run(t, func(o *op.Ops) { + // Draw a rectangle + paint.ColorOp{Color: colornames.Black}.Add(o) + paint.PaintOp{Rect: f32.Rect(0, 0, 128, 50)}.Add(o) + + builder := clip.Path{} + builder.Begin(o) + builder.Move(f32.Pt(0, 0)) + builder.Line(f32.Pt(10, 0)) + builder.Line(f32.Pt(0, 10)) + builder.Line(f32.Pt(-10, 0)) + builder.Line(f32.Pt(0, -10)) + builder.End().Add(o) + paint.ColorOp{Color: colornames.Red}.Add(o) + paint.PaintOp{Rect: f32.Rect(0, 0, 10, 10)}.Add(o) + }, func(r result) { + r.expect(5, 5, colornames.Red) + r.expect(11, 15, colornames.Black) + r.expect(11, 51, colornames.White) + }) +} + +func TestNoClipFromPaint(t *testing.T) { + // ensure that a paint operation does not polute the state + // by leaving any clip paths i place. + run(t, func(o *op.Ops) { + a := f32.Affine2D{}.Rotate(f32.Pt(20, 20), math.Pi/4) + op.Affine(a).Add(o) + paint.ColorOp{Color: colornames.Red}.Add(o) + paint.PaintOp{Rect: f32.Rect(10, 10, 30, 30)}.Add(o) + a = f32.Affine2D{}.Rotate(f32.Pt(20, 20), -math.Pi/4) + op.Affine(a).Add(o) + + paint.ColorOp{Color: colornames.Black}.Add(o) + paint.PaintOp{Rect: f32.Rect(0, 0, 50, 50)}.Add(o) + }, func(r result) { + r.expect(1, 1, colornames.Black) + r.expect(20, 20, colornames.Black) + r.expect(49, 49, colornames.Black) + r.expect(51, 51, colornames.White) + }) +} + +func createText() op.CallOp { + innerOps := new(op.Ops) + m := op.Record(innerOps) + builder := clip.Path{} + builder.Begin(innerOps) + builder.Move(f32.Pt(0, 0)) + builder.Line(f32.Pt(10, 0)) + builder.Line(f32.Pt(0, 10)) + builder.Line(f32.Pt(-10, 0)) + builder.Line(f32.Pt(0, -10)) + builder.End().Add(innerOps) + return m.Stop() +} + +func drawChild(ops *op.Ops, text op.CallOp) op.CallOp { + r1 := op.Record(ops) + text.Add(ops) + paint.PaintOp{Rect: f32.Rect(0, 0, 10, 10)}.Add(ops) + return r1.Stop() +} + +func TestReuseStencil(t *testing.T) { + txt := createText() + run(t, func(ops *op.Ops) { + c1 := drawChild(ops, txt) + c2 := drawChild(ops, txt) + + // lay out the children + stack1 := op.Push(ops) + c1.Add(ops) + stack1.Pop() + + stack2 := op.Push(ops) + op.TransformOp{}.Offset(f32.Pt(0, 50)).Add(ops) + c2.Add(ops) + stack2.Pop() + }, func(r result) { + r.expect(5, 5, colornames.Black) + r.expect(5, 55, colornames.Black) + }) +} diff --git a/internal/rendertest/transform_test.go b/internal/rendertest/transform_test.go new file mode 100644 index 00000000..ed7a1d2f --- /dev/null +++ b/internal/rendertest/transform_test.go @@ -0,0 +1,201 @@ +package rendertest + +import ( + "math" + "testing" + + "gioui.org/f32" + "gioui.org/op" + "gioui.org/op/clip" + "gioui.org/op/paint" + "golang.org/x/image/colornames" +) + +func TestPaintOffset(t *testing.T) { + run(t, func(o *op.Ops) { + op.Offset(f32.Pt(10, 20)).Add(o) + paint.ColorOp{Color: colornames.Red}.Add(o) + paint.PaintOp{Rect: f32.Rect(0, 0, 50, 50)}.Add(o) + }, func(r result) { + r.expect(0, 0, colornames.White) + r.expect(59, 30, colornames.Red) + r.expect(60, 30, colornames.White) + r.expect(10, 70, colornames.White) + }) +} + +func TestPaintRotate(t *testing.T) { + run(t, func(o *op.Ops) { + a := f32.Affine2D{}.Rotate(f32.Pt(40, 40), -math.Pi/8) + op.Affine(a).Add(o) + paint.ColorOp{Color: colornames.Red}.Add(o) + paint.PaintOp{Rect: f32.Rect(20, 20, 60, 60)}.Add(o) + }, func(r result) { + r.expect(40, 40, colornames.Red) + r.expect(50, 19, colornames.Red) + r.expect(59, 19, colornames.White) + r.expect(21, 21, colornames.White) + }) +} + +func TestPaintShear(t *testing.T) { + run(t, func(o *op.Ops) { + a := f32.Affine2D{}.Shear(f32.Point{}, math.Pi/4, 0) + op.Affine(a).Add(o) + paint.ColorOp{Color: colornames.Red}.Add(o) + paint.PaintOp{Rect: f32.Rect(0, 0, 40, 40)}.Add(o) + }, func(r result) { + r.expect(10, 30, colornames.White) + }) +} + +func TestClipPaintOffset(t *testing.T) { + run(t, func(o *op.Ops) { + paint.ColorOp{Color: colornames.Red}.Add(o) + clip.Rect{Rect: f32.Rect(10, 10, 30, 30)}.Add(o) + op.Offset(f32.Pt(20, 20)).Add(o) + paint.PaintOp{Rect: f32.Rect(0, 0, 100, 100)}.Add(o) + }, func(r result) { + r.expect(0, 0, colornames.White) + r.expect(19, 19, colornames.White) + r.expect(20, 20, colornames.Red) + r.expect(30, 30, colornames.White) + }) +} + +func TestClipOffset(t *testing.T) { + run(t, func(o *op.Ops) { + paint.ColorOp{Color: colornames.Red}.Add(o) + op.Offset(f32.Pt(20, 20)).Add(o) + clip.Rect{Rect: f32.Rect(10, 10, 30, 30)}.Add(o) + paint.PaintOp{Rect: f32.Rect(0, 0, 100, 100)}.Add(o) + }, func(r result) { + r.expect(0, 0, colornames.White) + r.expect(29, 29, colornames.White) + r.expect(30, 30, colornames.Red) + r.expect(49, 49, colornames.Red) + r.expect(50, 50, colornames.White) + }) +} + +func TestClipScale(t *testing.T) { + run(t, func(o *op.Ops) { + paint.ColorOp{Color: colornames.Red}.Add(o) + a := f32.Affine2D{}.Scale(f32.Point{}, f32.Pt(2, 2)).Offset(f32.Pt(10, 10)) + op.Affine(a).Add(o) + clip.Rect{Rect: f32.Rect(10, 10, 20, 20)}.Add(o) + paint.PaintOp{Rect: f32.Rect(0, 0, 1000, 1000)}.Add(o) + }, func(r result) { + r.expect(19+10, 19+10, colornames.White) + r.expect(20+10, 20+10, colornames.Red) + r.expect(39+10, 39+10, colornames.Red) + r.expect(40+10, 40+10, colornames.White) + }) +} + +func TestClipRotate(t *testing.T) { + run(t, func(o *op.Ops) { + paint.ColorOp{Color: colornames.Red}.Add(o) + op.Affine(f32.Affine2D{}.Rotate(f32.Pt(40, 40), -math.Pi/4)).Add(o) + clip.Rect{Rect: f32.Rect(30, 30, 50, 50)}.Add(o) + paint.PaintOp{Rect: f32.Rect(0, 40, 100, 100)}.Add(o) + }, func(r result) { + r.expect(39, 39, colornames.White) + r.expect(41, 41, colornames.Red) + r.expect(50, 50, colornames.White) + }) +} + +func TestOffsetTexture(t *testing.T) { + run(t, func(o *op.Ops) { + op.Offset(f32.Pt(15, 15)).Add(o) + squares.Add(o) + paint.PaintOp{Rect: f32.Rect(0, 0, 50, 50)}.Add(o) + }, func(r result) { + r.expect(14, 20, colornames.White) + r.expect(66, 20, colornames.White) + r.expect(16, 64, colornames.Green) + r.expect(64, 16, colornames.Green) + }) +} + +func TestOffsetScaleTexture(t *testing.T) { + run(t, func(o *op.Ops) { + op.Offset(f32.Pt(15, 15)).Add(o) + squares.Add(o) + op.Affine(f32.Affine2D{}.Scale(f32.Point{}, f32.Pt(2, 1))).Add(o) + paint.PaintOp{Rect: f32.Rect(0, 0, 50, 50)}.Add(o) + }, func(r result) { + r.expect(114, 64, colornames.Blue) + r.expect(116, 64, colornames.White) + }) +} + +func TestRotateTexture(t *testing.T) { + run(t, func(o *op.Ops) { + squares.Add(o) + a := f32.Affine2D{}.Rotate(f32.Pt(40, 40), math.Pi/4) + op.Affine(a).Add(o) + paint.PaintOp{Rect: f32.Rect(30, 30, 50, 50)}.Add(o) + }, func(r result) { + r.expect(40, 40-12, colornames.Blue) + r.expect(40+12, 40, colornames.Green) + }) +} + +func TestRotateClipTexture(t *testing.T) { + run(t, func(o *op.Ops) { + squares.Add(o) + a := f32.Affine2D{}.Rotate(f32.Pt(40, 40), math.Pi/8) + op.Affine(a).Add(o) + clip.Rect{Rect: f32.Rect(30, 30, 50, 50)}.Add(o) + paint.PaintOp{Rect: f32.Rect(10, 10, 70, 70)}.Add(o) + }, func(r result) { + r.expect(0, 0, colornames.White) + r.expect(37, 39, colornames.Green) + r.expect(36, 39, colornames.Green) + r.expect(35, 39, colornames.Green) + r.expect(34, 39, colornames.Green) + r.expect(33, 39, colornames.Green) + }) +} + +func TestComplicatedTransform(t *testing.T) { + run(t, func(o *op.Ops) { + squares.Add(o) + + clip.Rect{Rect: f32.Rect(0, 0, 100, 100), SE: 50, SW: 50, NW: 50, NE: 50}.Add(o) + + a := f32.Affine2D{}.Shear(f32.Point{}, math.Pi/4, 0) + op.Affine(a).Add(o) + clip.Rect{Rect: f32.Rect(0, 0, 50, 40)}.Add(o) + + op.Offset(f32.Pt(-100, -100)).Add(o) + paint.PaintOp{Rect: f32.Rect(100, 100, 150, 150)}.Add(o) + }, func(r result) { + r.expect(20, 5, colornames.White) + }) +} + +func TestTransformOrder(t *testing.T) { + // check the ordering of operations bot in affine and in gpu stack. + run(t, func(o *op.Ops) { + paint.ColorOp{Color: colornames.Red}.Add(o) + + a := f32.Affine2D{}.Offset(f32.Pt(64, 64)) + op.Affine(a).Add(o) + + b := f32.Affine2D{}.Scale(f32.Point{}, f32.Pt(8, 8)) + op.Affine(b).Add(o) + + c := f32.Affine2D{}.Offset(f32.Pt(-10, -10)).Scale(f32.Point{}, f32.Pt(0.5, 0.5)) + op.Affine(c).Add(o) + paint.PaintOp{Rect: f32.Rect(0, 0, 20, 20)}.Add(o) + }, func(r result) { + // centered and with radius 40 + r.expect(64-41, 64, colornames.White) + r.expect(64-39, 64, colornames.Red) + r.expect(64+39, 64, colornames.Red) + r.expect(64+41, 64, colornames.White) + }) +} diff --git a/internal/rendertest/util_test.go b/internal/rendertest/util_test.go index f0ee0ed7..a8754be4 100644 --- a/internal/rendertest/util_test.go +++ b/internal/rendertest/util_test.go @@ -38,33 +38,40 @@ func init() { squares = paint.NewImageOp(im) } -func drawImage(size int, draw func(o *op.Ops)) (im *image.RGBA, err error) { +func drawImage(size int, ops *op.Ops, draw func(o *op.Ops)) (im *image.RGBA, err error) { sz := image.Point{X: size, Y: size} w, err := headless.NewWindow(sz.X, sz.Y) if err != nil { return im, err } - ops := new(op.Ops) draw(ops) w.Frame(ops) return w.Screenshot() } -func run(t *testing.T, f func(o *op.Ops)) result { - img, err := drawImage(128, f) - if err != nil { - t.Error("error rendering:", err) +func run(t *testing.T, f func(o *op.Ops), c func(r result)) { + // draw a few times and check that it is correct each time, to + // ensure any caching effects still generate the correct images. + ok := true + var img *image.RGBA + var err error + ops := new(op.Ops) + for i := 0; i < 3; i++ { + ops.Reset() + img, err = drawImage(128, ops, f) + if err != nil { + t.Error("error rendering:", err) + } + // check for a reference image and make sure we are identical. + ok = ok && verifyRef(t, img) + c(result{t: t, img: img}) } - // check for a reference image and make sure we are identical. - ok := verifyRef(t, img) - if *dumpImages || !ok { if err := saveImage(t.Name()+".png", img); err != nil { t.Error(err) } } - return result{t: t, img: img} } func verifyRef(t *testing.T, img *image.RGBA) (ok bool) {