Commit b39afde8 authored by Nigel Tao's avatar Nigel Tao

image/draw: add draw tests where the destination image doesn't start

at (0, 0).

Also refactor the test to use the SubImage method rather than monkeying
with an image's Pix and Rect fields.

R=r
CC=golang-dev
https://golang.org/cl/4678045
parent d1d466f6
...@@ -154,22 +154,32 @@ var drawTests = []drawTest{ ...@@ -154,22 +154,32 @@ var drawTests = []drawTest{
{"genericSrc", fillBlue(255), vgradAlpha(192), Src, image.RGBAColor{0, 0, 102, 102}}, {"genericSrc", fillBlue(255), vgradAlpha(192), Src, image.RGBAColor{0, 0, 102, 102}},
} }
func makeGolden(dst, src, mask image.Image, op Op) image.Image { func makeGolden(dst image.Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) image.Image {
// Since golden is a newly allocated image, we don't have to check if the // 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. // input source and mask images and the output golden image overlap.
b := dst.Bounds() b := dst.Bounds()
sx0 := src.Bounds().Min.X - b.Min.X sb := src.Bounds()
sy0 := src.Bounds().Min.Y - b.Min.Y mb := image.Rect(-1e9, -1e9, 1e9, 1e9)
var mx0, my0 int
if mask != nil { if mask != nil {
mx0 = mask.Bounds().Min.X - b.Min.X mb = mask.Bounds()
my0 = mask.Bounds().Min.Y - b.Min.Y
} }
golden := image.NewRGBA(b.Max.X, b.Max.Y) golden := image.NewRGBA(b.Max.X, b.Max.Y)
for y := b.Min.Y; y < b.Max.Y; y++ { for y := r.Min.Y; y < r.Max.Y; y++ {
my, sy := my0+y, sy0+y sy := y + sp.Y - r.Min.Y
for x := b.Min.X; x < b.Max.X; x++ { my := y + mp.Y - r.Min.Y
mx, sx := mx0+x, sx0+x for x := r.Min.X; x < r.Max.X; x++ {
if !(image.Point{x, y}.In(b)) {
continue
}
sx := x + sp.X - r.Min.X
if !(image.Point{sx, sy}.In(sb)) {
continue
}
mx := x + mp.X - r.Min.X
if !(image.Point{mx, my}.In(mb)) {
continue
}
const M = 1<<16 - 1 const M = 1<<16 - 1
var dr, dg, db, da uint32 var dr, dg, db, da uint32
if op == Over { if op == Over {
...@@ -189,39 +199,53 @@ func makeGolden(dst, src, mask image.Image, op Op) image.Image { ...@@ -189,39 +199,53 @@ func makeGolden(dst, src, mask image.Image, op Op) image.Image {
}) })
} }
} }
golden.Rect = b return golden.SubImage(b)
return golden
} }
func TestDraw(t *testing.T) { func TestDraw(t *testing.T) {
loop: rr := []image.Rectangle{
image.Rect(0, 0, 0, 0),
image.Rect(0, 0, 16, 16),
image.Rect(3, 5, 12, 10),
image.Rect(0, 0, 9, 9),
image.Rect(8, 8, 16, 16),
image.Rect(8, 0, 9, 16),
image.Rect(0, 8, 16, 9),
image.Rect(8, 8, 9, 9),
image.Rect(8, 8, 8, 8),
}
for _, r := range rr {
loop:
for _, test := range drawTests { for _, test := range drawTests {
dst := hgradRed(255) dst := hgradRed(255).(*image.RGBA).SubImage(r).(Image)
// Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation. // Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
golden := makeGolden(dst, test.src, test.mask, test.op) golden := makeGolden(dst, image.Rect(0, 0, 16, 16), test.src, image.ZP, test.mask, image.ZP, test.op)
b := dst.Bounds() b := dst.Bounds()
if !b.Eq(golden.Bounds()) { if !b.Eq(golden.Bounds()) {
t.Errorf("draw %s: bounds %v versus %v", test.desc, dst.Bounds(), golden.Bounds()) t.Errorf("draw %v %s: bounds %v versus %v", r, test.desc, dst.Bounds(), golden.Bounds())
continue continue
} }
// Draw the same combination onto the actual dst using the optimized DrawMask implementation. // Draw the same combination onto the actual dst using the optimized DrawMask implementation.
DrawMask(dst, b, test.src, image.ZP, test.mask, image.ZP, test.op) DrawMask(dst, image.Rect(0, 0, 16, 16), test.src, image.ZP, test.mask, image.ZP, test.op)
if image.Pt(8, 8).In(r) {
// Check that the resultant pixel at (8, 8) matches what we expect // Check that the resultant pixel at (8, 8) matches what we expect
// (the expected value can be verified by hand). // (the expected value can be verified by hand).
if !eq(dst.At(8, 8), test.expected) { if !eq(dst.At(8, 8), test.expected) {
t.Errorf("draw %s: at (8, 8) %v versus %v", test.desc, dst.At(8, 8), test.expected) t.Errorf("draw %v %s: at (8, 8) %v versus %v", r, test.desc, dst.At(8, 8), test.expected)
continue continue
} }
}
// Check that the resultant dst image matches the golden output. // Check that the resultant dst image matches the golden output.
for y := b.Min.Y; y < b.Max.Y; y++ { for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ { for x := b.Min.X; x < b.Max.X; x++ {
if !eq(dst.At(x, y), golden.At(x, y)) { 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)) t.Errorf("draw %v %s: at (%d, %d), %v versus golden %v", r, test.desc, x, y, dst.At(x, y), golden.At(x, y))
continue loop continue loop
} }
} }
} }
} }
}
} }
func TestDrawOverlap(t *testing.T) { func TestDrawOverlap(t *testing.T) {
...@@ -230,19 +254,11 @@ func TestDrawOverlap(t *testing.T) { ...@@ -230,19 +254,11 @@ func TestDrawOverlap(t *testing.T) {
loop: loop:
for xoff := -2; xoff <= 2; xoff++ { for xoff := -2; xoff <= 2; xoff++ {
m := gradYellow(127).(*image.RGBA) m := gradYellow(127).(*image.RGBA)
dst := &image.RGBA{ dst := m.SubImage(image.Rect(5, 5, 10, 10)).(*image.RGBA)
Pix: m.Pix, src := m.SubImage(image.Rect(5+xoff, 5+yoff, 10+xoff, 10+yoff)).(*image.RGBA)
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() b := dst.Bounds()
// Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
golden := makeGolden(dst, b, src, src.Bounds().Min, nil, image.ZP, op)
if !b.Eq(golden.Bounds()) { if !b.Eq(golden.Bounds()) {
t.Errorf("drawOverlap xoff=%d,yoff=%d: bounds %v versus %v", xoff, yoff, dst.Bounds(), golden.Bounds()) t.Errorf("drawOverlap xoff=%d,yoff=%d: bounds %v versus %v", xoff, yoff, dst.Bounds(), golden.Bounds())
continue continue
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment