summaryrefslogtreecommitdiff
path: root/src/pkg/exp/draw/draw_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/exp/draw/draw_test.go')
-rw-r--r--src/pkg/exp/draw/draw_test.go129
1 files changed, 96 insertions, 33 deletions
diff --git a/src/pkg/exp/draw/draw_test.go b/src/pkg/exp/draw/draw_test.go
index e9fde2535..90c9e823d 100644
--- a/src/pkg/exp/draw/draw_test.go
+++ b/src/pkg/exp/draw/draw_test.go
@@ -16,11 +16,11 @@ func eq(c0, c1 image.Color) bool {
}
func fillBlue(alpha int) image.Image {
- return image.ColorImage{image.RGBAColor{0, 0, uint8(alpha), uint8(alpha)}}
+ return image.NewColorImage(image.RGBAColor{0, 0, uint8(alpha), uint8(alpha)})
}
func fillAlpha(alpha int) image.Image {
- return image.ColorImage{image.AlphaColor{uint8(alpha)}}
+ return image.NewColorImage(image.AlphaColor{uint8(alpha)})
}
func vgradGreen(alpha int) image.Image {
@@ -53,6 +53,16 @@ func hgradRed(alpha int) Image {
return m
}
+func gradYellow(alpha int) Image {
+ m := image.NewRGBA(16, 16)
+ for y := 0; y < 16; y++ {
+ for x := 0; x < 16; x++ {
+ m.Set(x, y, image.RGBAColor{uint8(x * alpha / 15), uint8(y * alpha / 15), 0, uint8(alpha)})
+ }
+ }
+ return m
+}
+
type drawTest struct {
desc string
src image.Image
@@ -63,54 +73,62 @@ type drawTest struct {
var drawTests = []drawTest{
// Uniform mask (0% opaque).
- drawTest{"nop", vgradGreen(255), fillAlpha(0), Over, image.RGBAColor{136, 0, 0, 255}},
- drawTest{"clear", vgradGreen(255), fillAlpha(0), Src, image.RGBAColor{0, 0, 0, 0}},
+ {"nop", vgradGreen(255), fillAlpha(0), Over, image.RGBAColor{136, 0, 0, 255}},
+ {"clear", vgradGreen(255), fillAlpha(0), Src, image.RGBAColor{0, 0, 0, 0}},
// Uniform mask (100%, 75%, nil) and uniform source.
// At (x, y) == (8, 8):
// The destination pixel is {136, 0, 0, 255}.
// The source pixel is {0, 0, 90, 90}.
- drawTest{"fill", fillBlue(90), fillAlpha(255), Over, image.RGBAColor{88, 0, 90, 255}},
- drawTest{"fillSrc", fillBlue(90), fillAlpha(255), Src, image.RGBAColor{0, 0, 90, 90}},
- drawTest{"fillAlpha", fillBlue(90), fillAlpha(192), Over, image.RGBAColor{100, 0, 68, 255}},
- drawTest{"fillAlphaSrc", fillBlue(90), fillAlpha(192), Src, image.RGBAColor{0, 0, 68, 68}},
- drawTest{"fillNil", fillBlue(90), nil, Over, image.RGBAColor{88, 0, 90, 255}},
- drawTest{"fillNilSrc", fillBlue(90), nil, Src, image.RGBAColor{0, 0, 90, 90}},
+ {"fill", fillBlue(90), fillAlpha(255), Over, image.RGBAColor{88, 0, 90, 255}},
+ {"fillSrc", fillBlue(90), fillAlpha(255), Src, image.RGBAColor{0, 0, 90, 90}},
+ {"fillAlpha", fillBlue(90), fillAlpha(192), Over, image.RGBAColor{100, 0, 68, 255}},
+ {"fillAlphaSrc", fillBlue(90), fillAlpha(192), Src, image.RGBAColor{0, 0, 68, 68}},
+ {"fillNil", fillBlue(90), nil, Over, image.RGBAColor{88, 0, 90, 255}},
+ {"fillNilSrc", fillBlue(90), nil, Src, image.RGBAColor{0, 0, 90, 90}},
// Uniform mask (100%, 75%, nil) and variable source.
// At (x, y) == (8, 8):
// The destination pixel is {136, 0, 0, 255}.
// The source pixel is {0, 48, 0, 90}.
- drawTest{"copy", vgradGreen(90), fillAlpha(255), Over, image.RGBAColor{88, 48, 0, 255}},
- drawTest{"copySrc", vgradGreen(90), fillAlpha(255), Src, image.RGBAColor{0, 48, 0, 90}},
- drawTest{"copyAlpha", vgradGreen(90), fillAlpha(192), Over, image.RGBAColor{100, 36, 0, 255}},
- drawTest{"copyAlphaSrc", vgradGreen(90), fillAlpha(192), Src, image.RGBAColor{0, 36, 0, 68}},
- drawTest{"copyNil", vgradGreen(90), nil, Over, image.RGBAColor{88, 48, 0, 255}},
- drawTest{"copyNilSrc", vgradGreen(90), nil, Src, image.RGBAColor{0, 48, 0, 90}},
+ {"copy", vgradGreen(90), fillAlpha(255), Over, image.RGBAColor{88, 48, 0, 255}},
+ {"copySrc", vgradGreen(90), fillAlpha(255), Src, image.RGBAColor{0, 48, 0, 90}},
+ {"copyAlpha", vgradGreen(90), fillAlpha(192), Over, image.RGBAColor{100, 36, 0, 255}},
+ {"copyAlphaSrc", vgradGreen(90), fillAlpha(192), Src, image.RGBAColor{0, 36, 0, 68}},
+ {"copyNil", vgradGreen(90), nil, Over, image.RGBAColor{88, 48, 0, 255}},
+ {"copyNilSrc", vgradGreen(90), nil, Src, image.RGBAColor{0, 48, 0, 90}},
// Variable mask and variable source.
// At (x, y) == (8, 8):
// The destination pixel is {136, 0, 0, 255}.
// The source pixel is {0, 0, 255, 255}.
// The mask pixel's alpha is 102, or 40%.
- drawTest{"generic", fillBlue(255), vgradAlpha(192), Over, image.RGBAColor{81, 0, 102, 255}},
- drawTest{"genericSrc", fillBlue(255), vgradAlpha(192), Src, image.RGBAColor{0, 0, 102, 102}},
+ {"generic", fillBlue(255), vgradAlpha(192), Over, image.RGBAColor{81, 0, 102, 255}},
+ {"genericSrc", fillBlue(255), vgradAlpha(192), Src, image.RGBAColor{0, 0, 102, 102}},
}
-func makeGolden(dst image.Image, t drawTest) image.Image {
+func makeGolden(dst, src, mask image.Image, op Op) image.Image {
// Since golden is a newly allocated image, we don't have to check if the
// input source and mask images and the output golden image overlap.
- golden := image.NewRGBA(dst.Width(), dst.Height())
- for y := 0; y < golden.Height(); y++ {
- my, sy := y, y
- for x := 0; x < golden.Width(); x++ {
- mx, sx := x, x
+ b := dst.Bounds()
+ sx0 := src.Bounds().Min.X - b.Min.X
+ sy0 := src.Bounds().Min.Y - b.Min.Y
+ var mx0, my0 int
+ if mask != nil {
+ mx0 = mask.Bounds().Min.X - b.Min.X
+ my0 = mask.Bounds().Min.Y - b.Min.Y
+ }
+ golden := image.NewRGBA(b.Max.X, b.Max.Y)
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ my, sy := my0+y, sy0+y
+ for x := b.Min.X; x < b.Max.X; x++ {
+ mx, sx := mx0+x, sx0+x
const M = 1<<16 - 1
var dr, dg, db, da uint32
- if t.op == Over {
+ if op == Over {
dr, dg, db, da = dst.At(x, y).RGBA()
}
- sr, sg, sb, sa := t.src.At(sx, sy).RGBA()
+ sr, sg, sb, sa := src.At(sx, sy).RGBA()
ma := uint32(M)
- if t.mask != nil {
- _, _, _, ma = t.mask.At(mx, my).RGBA()
+ if mask != nil {
+ _, _, _, ma = mask.At(mx, my).RGBA()
}
a := M - (sa * ma / M)
golden.Set(x, y, image.RGBA64Color{
@@ -121,6 +139,7 @@ func makeGolden(dst image.Image, t drawTest) image.Image {
})
}
}
+ golden.Rect = b
return golden
}
@@ -129,9 +148,14 @@ loop:
for _, test := range drawTests {
dst := hgradRed(255)
// Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
- golden := makeGolden(dst, test)
+ golden := makeGolden(dst, test.src, test.mask, test.op)
+ b := dst.Bounds()
+ if !b.Eq(golden.Bounds()) {
+ t.Errorf("draw %s: bounds %v versus %v", test.desc, dst.Bounds(), golden.Bounds())
+ continue
+ }
// Draw the same combination onto the actual dst using the optimized DrawMask implementation.
- DrawMask(dst, Rect(0, 0, dst.Width(), dst.Height()), test.src, ZP, test.mask, ZP, test.op)
+ DrawMask(dst, b, test.src, image.ZP, test.mask, image.ZP, test.op)
// Check that the resultant pixel at (8, 8) matches what we expect
// (the expected value can be verified by hand).
if !eq(dst.At(8, 8), test.expected) {
@@ -139,8 +163,8 @@ loop:
continue
}
// Check that the resultant dst image matches the golden output.
- for y := 0; y < golden.Height(); y++ {
- for x := 0; x < golden.Width(); x++ {
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
if !eq(dst.At(x, y), golden.At(x, y)) {
t.Errorf("draw %s: at (%d, %d), %v versus golden %v", test.desc, x, y, dst.At(x, y), golden.At(x, y))
continue loop
@@ -150,6 +174,45 @@ loop:
}
}
+func TestDrawOverlap(t *testing.T) {
+ for _, op := range []Op{Over, Src} {
+ for yoff := -2; yoff <= 2; yoff++ {
+ loop:
+ for xoff := -2; xoff <= 2; xoff++ {
+ m := gradYellow(127).(*image.RGBA)
+ dst := &image.RGBA{
+ Pix: m.Pix,
+ Stride: m.Stride,
+ Rect: image.Rect(5, 5, 10, 10),
+ }
+ src := &image.RGBA{
+ Pix: m.Pix,
+ Stride: m.Stride,
+ Rect: image.Rect(5+xoff, 5+yoff, 10+xoff, 10+yoff),
+ }
+ // Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
+ golden := makeGolden(dst, src, nil, op)
+ b := dst.Bounds()
+ if !b.Eq(golden.Bounds()) {
+ t.Errorf("drawOverlap xoff=%d,yoff=%d: bounds %v versus %v", xoff, yoff, dst.Bounds(), golden.Bounds())
+ continue
+ }
+ // Draw the same combination onto the actual dst using the optimized DrawMask implementation.
+ DrawMask(dst, b, src, src.Bounds().Min, nil, image.ZP, op)
+ // Check that the resultant dst image matches the golden output.
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ if !eq(dst.At(x, y), golden.At(x, y)) {
+ t.Errorf("drawOverlap xoff=%d,yoff=%d: at (%d, %d), %v versus golden %v", xoff, yoff, x, y, dst.At(x, y), golden.At(x, y))
+ continue loop
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
// TestIssue836 verifies http://code.google.com/p/go/issues/detail?id=836.
func TestIssue836(t *testing.T) {
a := image.NewRGBA(1, 1)
@@ -158,7 +221,7 @@ func TestIssue836(t *testing.T) {
b.Set(1, 0, image.RGBAColor{0, 0, 5, 5})
b.Set(0, 1, image.RGBAColor{0, 5, 0, 5})
b.Set(1, 1, image.RGBAColor{5, 0, 0, 5})
- Draw(a, Rect(0, 0, 1, 1), b, Pt(1, 1))
+ Draw(a, image.Rect(0, 0, 1, 1), b, image.Pt(1, 1))
if !eq(image.RGBAColor{5, 0, 0, 5}, a.At(0, 0)) {
t.Errorf("Issue 836: want %v got %v", image.RGBAColor{5, 0, 0, 5}, a.At(0, 0))
}